diff options
Diffstat (limited to '_posts/2017-09-28-perl6-creating-a-background-service.adoc')
-rw-r--r-- | _posts/2017-09-28-perl6-creating-a-background-service.adoc | 159 |
1 files changed, 0 insertions, 159 deletions
diff --git a/_posts/2017-09-28-perl6-creating-a-background-service.adoc b/_posts/2017-09-28-perl6-creating-a-background-service.adoc deleted file mode 100644 index 4cc759d..0000000 --- a/_posts/2017-09-28-perl6-creating-a-background-service.adoc +++ /dev/null @@ -1,159 +0,0 @@ ---- -date: 2017-09-28 15:11:43 -tags: Tutorial Perl6 Programming Raku -description: > - I've recently made some progress on Shinrin, a centralized logging system in - Perl 6. This has to run as service, which means that for most service - managers it has to be able to run in the background. ---- -= Perl 6 - Creating a background service -:toc: preamble - -I've recently made some progress on -https://github.com/scriptkitties/perl6-Shinrin[Shinrin], a centralized logging -system in Perl 6. This has to run as service, which means that for most service -managers it has to be able to run in the background. - -[NOTE] -==== -If you just want to get to the solution and don't care for the details, just -head straight to link:#the-final-solution[the full script]. -==== - -== It's not possible! -After a lot of trying and talking with the folks at -irc://chat.freenode.net:6697/#perl6[#perl6] I was told that it is not possible -to do this in pure Perl 6, explained by people with more knowledge than I have -on the internals: - -[quote, jnthn] -____ -(jnthn suspects fork + multi-threaded VM = pain) Since fork only clones one -thread - the one that called it. So suddenly you've got an instance of the VM -missing most of its threads. -____ - -[quote, geekosaur] -____ -The most common failure mode is that some thread is holding e.g. a mutex (or a -userspace lock) during the fork. The thread goes away but the lock is process -level and remains, with nothing around to know to unlock it. So then things -work until something else needs that lock and suddenly you deadlock. -____ - -Not much later, `jnthn` https://github.com/perl6/doc/commit/8f9443c3ac[pushed a -commit] to update the docs to clarify that a `fork` call through `NativeCall` -will probably not give the result you were hoping for. - -== Or is it? -Luckily, the same people were able to think up of a work-around, which can be -made in POSIX sh, so it's usable on any decent OS. The workaround is to let a -little shell script fork into the background, and let that run the Perl -application. - -=== A first example -This is fairly simple to create, as in this example to launch `shinrind` in the -background: - -[source,sh] ----- -#! /usr/bin/env sh - -main() -{ - perl6 -Ilib bin/shinrind "$@" -} - -main "$@" & ----- - -This works just fine if the working directory is correct. This means you need -to be in the parent directory to `lib` and `bin` of the program to make it -work. - -== Improving the forking script -While that short script works fine to show a proof of concept, in order to make -it viable for real-world scenarios, it can use some improvements. After all, it -would be annoying if you'd have to `cd` to a specific directory any time you -want to start your application. - -=== Ensure you are in the directory you should be in -So for starters, let's make sure that you can run it from anywhere on your -system. For this, you should set the working directory for the script, so you -don't have to do it manually. Because the script runs in its own subshell, the -shell you're working from remains unaffected. - -A POSIX compliant way to get the directory the script is stored in is as -follows: - -[source,sh] ----- -DIR=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) ----- - -This will set `$DIR` to the path of the directory the shell script is stored -in. You can simply `cd` to that and be assured you're in the right directory. - -In Perl 6, it is expected for executable files to live in the `bin` directory -of your project repository. So you should actually be in the parent of the -directory holding your script. Furthermore, you should check the `cd` command -executed correctly, just to be safe. - -[source,sh] ----- -cd -- "${DIR}/.." || exit ----- - -=== Disable `STDOUT` and `STDERR` -A started service should not be polluting your interactive shell, so you should -disable (or otherwise redirect) `STDOUT` and `STDERR`. This is done in the -shell using a small bit of code behind whatever you want to redirect: - -[source,sh] ----- -> /dev/null 2>&1 ----- - -This will set `STDOUT` to `/dev/null`, and set `STDERR` to the same stream as -`STDOUT`, which in effect will make all output go to `/dev/null`. If you want -to log everything to a single file, you can replace `/dev/null` with another -file of your choice. If you don't want logs to be overwritten on each start, -use a `>>` instead of a single `>` at the start. - -If you want to log errors and output in different files, you can use the -following: - -[source,sh] ----- -> /var/log/service.log 2> /var/log/service.err ----- - -This will put standard output in `/var/log/service.log` and errors in -`/var/log/service.err`. - -=== Fork just the Perl 6 program -In the initial example, I put the `&` behind the `main` call, at the bottom of -the script. While this works just fine for most simple usage, if you want to do -additional chores, like creating a pidfile after starting the Perl 6 program, -you're out of luck. If you were to only fork the Perl 6 application, you could -handle some other cases in the shell script. - -== The final solution -For those eager to just get going with this, here is the complete example -script to just fork your Perl program into the background: - -[source,sh] ----- -#! /usr/bin/env sh - -readonly DIR=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) - -main() -{ - cd -- "${DIR}/.." || exit - - perl6 -Ilib bin/shinrind "$@" > /dev/null >2&1 & -} - -main "$@" ----- |