How to run a detached command and return execution to the parent script?

874 views
Skip to first unread message

Adrian Salceanu

unread,
Jan 22, 2016, 4:06:01 PM1/22/16
to julia-users
Hi, 

I'm hammering at a web app and I'm trying to setup functionality to monitor the file system for changes and restart/reload the server automatically so the changes are picked up (I'm using Mux which uses HttpServer). 

The approach I have in mind is: 

1. have a startup script which is run from the command line, something like: 
$ julia -L startup.jl

2. the startup script launches the web app, which starts the web server. My intention was to run 
$ julia -L app.jl 
as a command inside startup.jl, detached, and have the startup.jl script get back control, with app.jl running detached in the background. 

3. once startup.jl gets back control, it begins monitoring the file system and when changes are detected, kills the app and relaunches it. 

That was the theory. Now, I might be missing something but I can't find a way to detach the command I'm running and get control back to the startup script. And I tried a lot of things! 

===

I'm providing simpler example using "ping", which also run indefinitely, similar to the web server. 

julia> run(detach(`ping "www.google.com"`)) # the command is detached and continues to run after the julia REPL is closed, but at this point the REPL does not get control, there's no cursor available in the REPL
PING www.google.com (173.194.45.82): 56 data bytes
64 bytes from 173.194.45.82: icmp_seq=0 ttl=54 time=30.138 ms
64 bytes from 173.194.45.82: icmp_seq=1 ttl=54 time=30.417 ms
... more output ...
64 bytes from 173.194.45.82: icmp_seq=7 ttl=54 time=30.486 ms
64 bytes from 173.194.45.82: icmp_seq=8 ttl=54 time=30.173 ms
^CERROR: InterruptException:                                                                 <---- here I press Ctrl+C and only now the REPL gets back the cursor, with the command still running in the background

===

Also, related to this, passing "&" into the command to detach does not work as expected, the "&" is interpreted as argument of the command. Not sure if this would help anyway to return control to the startup.jl script? 

julia> run(detach(`ping "www.google.com" &`));
usage: ping [-AaDdfnoQqRrv] [-b boundif] [-c count] [-G sweepmaxsize]
            [-g sweepminsize] [-h sweepincrsize] [-i wait] [−k trafficclass]
            [-l preload] [-M mask | time] [-m ttl] [-p pattern]
            [-S src_addr] [-s packetsize] [-t timeout][-W waittime] [-z tos]
            host
       ping [-AaDdfLnoQqRrv] [-b boundif] [-c count] [-I iface] [-i wait]
            [−k trafficclass] [-l preload] [-M mask | time] [-m ttl] [-p pattern] [-S src_addr]
            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]
            [-z tos] mcast-group
ERROR: failed process: Process(`ping www.google.com &`, ProcessExited(64)) [64]
 in run at /usr/local/Cellar/julia/0.4.2/lib/julia/sys.dylib

===

Thanks

Adrian Salceanu

unread,
Jan 22, 2016, 4:29:27 PM1/22/16
to julia-users
I guess what I'm looking for is the equivalent of Ruby's Process#spawn

In REPL: 

>> pid = Process.spawn("ping www.google.com", :out => '/dev/null')
83210
>>                         <-- the process is running in the background and control has been returned to the REPL

Adrian Salceanu

unread,
Jan 22, 2016, 4:33:14 PM1/22/16
to julia-users
Oh! The ruby analogy made me think about actually spawning the detached command! Which produced the desired effect! 

julia> @spawn run(detach(`ping www.google.com`))

Stefan Karpinski

unread,
Jan 22, 2016, 4:40:56 PM1/22/16
to Julia Users
@spawn runs a command on a (random) worker process. If you want to do "background" work in the current process, you can use @async:

julia> t = @async (sleep(5); rand())
Task (runnable) @0x0000000112d746a0

julia> wait(t)
0.14543742643271207

Erik Schnetter

unread,
Jan 22, 2016, 4:45:10 PM1/22/16
to julia...@googlegroups.com
If you want to be able to terminate your local Julia process, and have
the server continue to run in the background, then you might want to
check out <https://github.com/eschnett/Persist.jl>. This does the
equivalent of run/detach, but in such a way that the detached process
runs as daemon.

Otherwise, if you don't need this functionality, then @async is the way to go.

-erik
--
Erik Schnetter <schn...@gmail.com>
http://www.perimeterinstitute.ca/personal/eschnetter/

Adrian Salceanu

unread,
Jan 22, 2016, 5:26:23 PM1/22/16
to julia-users
Thanks! 

@async works perfectly with your example. And also works great with running the "ping" command. The problem is web app / Mux / HttpServer exit immediately if run @async. Same with @spawn, the app exits immediately. 

Adrian Salceanu

unread,
Jan 22, 2016, 5:28:23 PM1/22/16
to julia-users
Thanks

Per my previous comment, unfortunately @async / @spawn cause the app / server to exit immediately. 

Let me give @persist a try. 

Cheers! 

Adrian Salceanu

unread,
Jan 22, 2016, 5:49:19 PM1/22/16
to julia-users
The problem seems to that HttpServer can not run @async - it exits immediately. 

===

using HttpServer

http = HttpHandler() do req::Request, res::Response
    Response( ismatch(r"^/hello/", req.resource) ? exit(2) : 404 )
end

server = Server( http )
run( server, 8001 )  # <--- this works but blocks
@async run( server, 8001 ) # <--- this exits immediately

===

It's not necessarily a problem that HttpServer blocks. But what drives me nuts is: if I run 
$ julia app.jl & 
in the shell, it works perfectly. The process is placed in the background, the server happily listens to the assigned port, etc. 

Why can't I run the same command from within another julia process and get the same effect? 


vineri, 22 ianuarie 2016, 22:40:56 UTC+1, Stefan Karpinski a scris:

Adrian Salceanu

unread,
Jan 22, 2016, 6:05:01 PM1/22/16
to julia-users
Oh, @async has worked actually! 

It correctly run the command, but the startup script itself was finishing and exiting immediately after. 

Thank you very much Stefan and Erik! 

Stefan Karpinski

unread,
Jan 22, 2016, 6:06:13 PM1/22/16
to Julia Users
The shell works with processes, Julia has tasks where are not the same thing...

Adrian Salceanu

unread,
Jan 22, 2016, 6:24:50 PM1/22/16
to julia-users
No no, It's perfectly fine, it was my fault. What I haven't realized is that if I start the server async then my script will finish immediately, which also terminated the server. It was my responsibility to keep the whole app alive now. 

It works like a charm! 

Stefan Karpinski

unread,
Jan 23, 2016, 1:01:24 PM1/23/16
to Julia Users
Great! I'm glad you got it sorted out.

Adrian Salceanu

unread,
Jan 25, 2016, 2:30:40 AM1/25/16
to julia-users
Cheers! 
Reply all
Reply to author
Forward
0 new messages