make a jruby program a windows service - windows-services

I have a JRuby program that I want to be a windows service. I have seen some things on creating a service with Ruby, but we don't want to install ruby on our client machines. It appears to be not supported in JRuby.
I created a dummy program to try this out:
path = "C:/tmp/my-svc.log"
if File.exists?(path)
File.open(path,"a"){|f| f.write(" called again\n")}
else
File.open(path,"w"){|f| f.write(" called first time\n")}
end
while true do
sleep 5
puts 'I am a service'
end
I did this:
Z:\play>sc.exe create "larz service 2.1" binpath= "C:\jruby-1.6.7.2\bin\jruby -S Z:\play\my-win-svc.rb" start= auto
[SC] CreateService SUCCESS
Trying to start it I got this error:
Z:\play>sc start "larz service 2.1"
[SC] StartService FAILED with error 193.
Z:\play>sc query "larz service 2.1"
SERVICE_NAME: larz service 2.1`
TYPE : 10 WIN32_OWN_PROCESS`
STATE : 1 STOPPED
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
I have seen alot of posts on the web on different ways to create windows services, using initsrv.exe, powershell, running CMD, editing the registry and so on, but I am not sure what is really going on or if I need to call some API. It doesn't appear as if the other approaches add any specific start parameters that I could tell. In addition, I added code at the beginning of my test service to write to a file in /tmp and the file is not being written so when I try to start the program, it never actually is being executed.
Thanks ..
Ok, so I got a little farther, but still mystified
Z:\play>sc config "larz service 2.2" obj= EEE\lgud password= "Ssssssss#"
[SC] ChangeServiceConfig SUCCESS
Z:\play>sc start "larz service 2.2"
[SC] StartService FAILED 1069:
the service did not start due to a logon failure.
It seems I entered the correct format for user/pw as at other times it errored out on the config command.

If you are positive that the password is correct, perhaps the user you have specified doesn't have the right privileges to run as a service. Try entering the account information on the Windows Services Application (services.msc) Log On tab, which will let you know if there is a problem with that user.
But beyond that, I don't see how you're going to get this going without Ruby installed. Your service's executable path is set to a .rb file -- what application do you expect Windows to launch to run that file, if not Ruby?

Related

How to rollback database in docker container using elixir phoenix releases and the example MyApp.Release.rollback in the guides

I cannot figure out how to rollback a database when trying to do it through a phoenix app running in a docker container. I am trying to simulate locally what it would be like when migrating on a remote server.
I am running it locally by running:
docker run -it -p 4000:4000 -e DATABASE_URL=ecto://postgres:postgres#host.docker.internal/my_app_dev -e SECRET_KEY_BASE=blahblah my-app-tag:v1
I view the running containers with:
docker ps
I bash into the container
docker exec -it 8943918c8f4f /bin/bash
cd into app/bin
cd bin
try to rollback
./my_app rpc 'MyApp.Release.rollback(MyApp.Repo, "20191106071140")'
=> 08:43:45.516 [info] Already down
If this did indeed work when running through the application it should blow up as I do different things. But it doesn't.
If I try eval
./my_app eval 'MyApp.Release.rollback(MyApp.Repo, "20191106071140")'
=>
08:46:22.033 [error] GenServer #PID<0.207.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
(elixir) lib/keyword.ex:393: Keyword.fetch!/2
(postgrex) lib/postgrex/protocol.ex:92: Postgrex.Protocol.connect/1
(db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
** (EXIT from #PID<0.163.0>) shutdown
I am trying to ensure I know how to deploy an application to a remote (Heroku, AWS) and have the application automatically migrate on every deploy but also have the option to run a command to roll back 1 step at a time.
I am not finding any information. The debugging above is first step in creating this migrate/rollback functionality on a remote server but testing on my local machine first.
The migrate/rollback code is taken directly from https://hexdocs.pm/phoenix/releases.html#ecto-migrations-and-custom-commands
Any help/direction would be greatly appreciated.
Thank you
In the first place, rpc call should succeed. Make sure you indeed have the migration in the question up before running my_app rpc. Note, that the second argument is the version to revert to, not the migration to revert.
Regarding the eval. One should start or at least load the application before any attempt to access its config. As per documentation:
You can start an application by calling Application.ensure_all_started/1. However, if for some reason you cannot start an application, maybe because it will run other services you do not want, you must at least load the application by calling Application.load/1. If you don't load the application, any attempt at reading its environment or configuration may fail. Note that if you start an application, it is automatically loaded before started.
For the migration to succeed, one needs Ecto aplication Ecto.Adapters.SQL.Application started and your application loaded (to access configs.)
That said, something like this should work.
def my_rollback(version) do
Application.load(:my_app)
Application.ensure_all_started(:ecto_sql)
Ecto.Migrator.with_repo(MyApp.Repo,
&Ecto.Migrator.run(&1, :down, to: version))
end
And call it as
./my_app eval 'MyApp.Release.my_rollback(20191106071140)'
Still, rpc should start the required applications out of the box (and it indeed does, according to the message you get back,) so I’d suggest you to triple-check the migration you are requesting to down is already up and you pass the proper version to downgrade to.
There were two issues here and thanks to #aleksei-matiushkin I got it working.
The first issue was not having Application.load(:my_app) in the function.
The second issue was that I was calling the rollback functions (both mine and #aleksei-matiushkin) as a string and not an int. Now I call it like: ./my_app eval 'MyApp.Release.my_rollback(20191106071140)'
The file now looks like this:
defmodule MyApp.Release do
#app :my_app
def migrate do
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
setup_for_rollback()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
def my_rollback(version) do
setup_for_rollback()
rollback(MyApp.Repo, version)
end
defp setup_for_rollback() do
Application.load(#app)
Application.ensure_all_started(:ecto_sql)
end
defp repos do
Application.load(#app)
Application.fetch_env!(#app, :ecto_repos)
end
end
I am not sure if this is an idiomatic implementation. I did not have any issues excluding Application.ensure_all_started(:ecto_sql) but since it was recommended I guess I'll leave it in.

Stopping OrientDB service fails, ETL import not possible

My goal is to import data from CSV-files into OrientDB.
I use the OrientDB 2.2.22 Docker image.
When I try to execute the /orientdb/bin/oetl.sh config.json script within Docker, I get the error: "Can not open storage it is acquired by other process".
I guess this is, because the OrientDB - service is still running. But, if I try to stop it i get the next error.
./orientdb.sh stop
./orientdb.sh: return: line 70: Illegal number: root
or
./orientdb.sh status
./orientdb.sh: return: line 89: Illegal number: root
The only way for to use the ./oetl.sh script is to stop the Docker instance and restart it in the interactive mode running the shell, but this is awkward because to use the "OrientDB Studio" I have to stop docker again and start it in the normal mode.
As Roberto Franchini mentioned above setting the dbURL parameter in the Loader to use a remote URL fixed the first issue "Can not open storage it is acquired by other process".
The issues with the .orientdb.sh still exists, but with the remote-URL approach I don't need to shutdown and restart the service anymore.

Service does not start

I created a Windows service with Delphi and used two method to install, start and stop.
Method 1
if i install this service using commandline
C:\MyService\ServiceApp.exe /Install
it installed successfully and i can start and stop too in the service console.
Method 2
but if i install the same service with different name using sc
e.g.
C:\Windows\system32>sc create myservice binpath= c:\MyService\ServiceApp.exe
I see it is installed but i can not start the service using service console as well as
with
sc start myservice
when i do query using SC , result are as follows
C:\Windows\system32>sc query myservice
SERVICE_NAME: myservice
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
up till now i was using /Install but i want to install same service multiple times with different names, I got this idea of using from this post. (How to install a windows service from command line specifying name and description?)
can anybody explain difference of behavior between /Install and SC?
You have clashed with a bug in TService implementation, see QC #79781. Delphi is not able to start the service if the service name if different from TService.Name.
However, you can avoid this limitation by adjusting TService.Name before the service is started. One good point to do this is the TService.OnCreate event. You need to know the real name of the service, so you need to pass it as an argument to the service exe (adding it to the binpath of the sc create command).
Create the service:
sc create myservice1 binpath= "c:\MyService\ServiceApp.exe myservice1"
sc create myservice2 binpath= "c:\MyService\ServiceApp.exe myservice2"
Adjust the name:
procedure TMyService.ServiceCreate(Sender: TObject);
begin
if (System.ParamCount >= 1) and not CharInSet(ParamStr(1)[1], SwitchChars) then
Name := ParamStr(1);
end;
This is a somewhat rudimentary method of argument parsing, but it is ok as an example. If the first argument doesn't start with / or -, it assumes that it's the supplied name.
Remark:
Another limitation of TService is that it can't create services (using /install) with arguments in their command line, because it uses ParamStr(0) as the binpath.

Automatic services do not start

I have a handful of console apps installed as services running under topshelf and if I install and run manually they work fine. However none automatically start even though the startup type is set to Automatic.
The apps are configured as follows:
HostFactory.Run(x =>
{
x.Service<MyApp>(s =>
{
s.ConstructUsing(name => container.Resolve<MyApp>());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc =>
{
tc.Stop();
container.Dispose();
});
});
x.RunAsLocalSystem();
x.StartAutomatically();
x.EnableServiceRecovery(rc => rc.RestartService(5));
});
The apps run under Win 2008 R2 and they are installed using a batch file executed as Admin. The batch file includes the following:
app.exe install --sudo
app.exe start
After executing the the batch file the services run as expected. However if I reboot they remain stopped.
The event log returns the same pair of events for each service:
Event 7000: The service failed to start due to the following error:
The service did not respond to the start or control request in a timely fashion.
Event 7009: A timeout was reached (30000 milliseconds) while waiting for the service to connect.
The only way to start the app after a reboot is to run app.exe start from an elevated command prompt.
Any ideas?
OK i've fixed it. The service startup types were set to Automatic but i've changed them to Automatic (Delayed) and all now run properly on start-up.
Also i've modified the install batch files for future use:
app.exe install --delayed --sudo
app.exe start
Only a guess, but probably dependent on network services which might not be available.
The most likely answer is that it's taking too long for the container to get created and resolved during start up when other stuff is happening on the machine. When you do it manually, nothing else is vying for resources. Can you defer some of the work done in your container until after creation & start? You can also request more time, but I don't recall that API off the top of my head.

Starting a user defined service in windows Xp

I am creating a user defined service on Windows Xp using sc.exe
To create I started with
sc.exe create "My Service" binPath= "D:\Service.bat"
Got a message CreateService SUCCESS.
Then I entered services.msc in the RUN and found the service which I created was there
Right clicked My Service then properties and when I started
I get an error as
ERROR 1053: The service did not respond to the start in a timely fashion
How do I fix this error.
Thanks
I think you need to enter cmd as command;
sc.exe create "My Service" binPath= "cmd /c D:\Service.bat"
And make sure the batch file does not stop too quick. At the first line of the batchfile let it write to a logfile, so you can see it is being executed. (and use a location where the service user may write to).
echo starting at %date% %time% > d:\service.log
As an alternative you can also use srvany.exe, see KB137890, but that is more hassle.

Resources