Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread NCrashed via Digitalmars-d-announce
Finally I've finished library for wrapping applications into 
daemons or services (Windows). The library hides 
platform-specific boilerplate behind compile-time API:

```
// First you need to describe your daemon via template
alias daemon = Daemon!(
DaemonizeExample1, // unique name

// Setting associative map signal - callbacks
KeyValueList!(
// You can bind same delegate for several signals by 
Composition template
// delegate can take additional argument to know which 
signal is caught
Composition!(Signal.Terminate, Signal.Quit, 
Signal.Shutdown, Signal.Stop), (logger, signal)

{
logger.logInfo(Exiting...);
return false; // returning false will terminate daemon
},
Signal.HangUp, (logger)
{
logger.logInfo(Hello World!);
return true; // continue execution
}
),

// Main function where your code is
(logger, shouldExit) {
// will stop the daemon in 5 minutes
auto time = Clock.currSystemTick + 
cast(TickDuration)5.dur!minutes;

while(!shouldExit()  time  Clock.currSystemTick) {  }

return 0;
}
);

int main()
{
return buildDaemon!daemon.run(new shared 
StrictLogger(logfile.log));

}
```

At the moment daemonize has following features:
* Daemons for GNU/Linux, services for Windows
* Custom signals
* Signal composition
* Client for sending signals to defined daemons
* Auto installing and uninstalling for Windows services
* Usage of .pid and .lock files (GNU/Linux)
* Privileges lowing (GNU/Linux)

Daemonize operates well with vibe.d (example - 
https://github.com/NCrashed/daemonize/tree/master/examples/03.Vibed)


P.S. At the moment library doesn't support Mac and other Posix 
systems, the support is going to be added at next releases.


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread ketmar via Digitalmars-d-announce
On Sun, 31 Aug 2014 11:27:41 +
NCrashed via Digitalmars-d-announce
digitalmars-d-announce@puremagic.com wrote:

looks very interesting, thank you.


signature.asc
Description: PGP signature


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread Philippe Sigaud via Digitalmars-d-announce
Nice!

I have a few questions/remarks, mainly to simplify the API somewhat.
Please bear with me :-)

 // First you need to describe your daemon via template
 alias daemon = Daemon!(
 DaemonizeExample1, // unique name

Does the user sees/uses this name in any way afterwards? Because I
think you could also produce a unique string at compile-time (by using
__FILE__ and __LINE__, unless someone has a better idea), if the user
does not provide one. Maybe he just wants an anonymous daemon, or
doesn't care, whatever.


 // Setting associative map signal - callbacks
 KeyValueList!(

If I understand correctly, the Daemon template waits for a list of (at
least one) Signal, then a delegate, then some more Signals, another
delegate, and so on?

If that's so I think you could ditch KeyValueList (or build it
invisibly to the user) and let the user write only the signals and
delegates:

alias daemon = Daemon!(
Signal.Terminate, Signal.Quit, Signal.Shutdown, Signal.Stop,
(logger, signal) {
...},
Signal.Hangup,
(logger) {
...}
...
);

Iterate the argument list, collecting Signals. When you hit a
delegate, create a Composition!( ... ) with the previous signals, jump
above the delegate and so on.

Is the idea that, if the delegate has two arguments, then the second
is the signal that will be passed to it, and if it has only one
argument, only the logger will be passed?

What if the user does not want a logger? Is a daemon always associated
to a log file in OSes?



 // Main function where your code is
 (logger, shouldExit) {
 // will stop the daemon in 5 minutes
 auto time = Clock.currSystemTick +
 cast(TickDuration)5.dur!minutes;
 while(!shouldExit()  time  Clock.currSystemTick) {  }

 return 0;
 }

Is the main function always the last delegate?

Concerning the DaemonClient template, could you not ask for Daemon to
generate it on demand? Or is DaemonClient always used in another
module?

Because, given a Daemon, extracting the simplified DaemonClient can be
done, I think.


 * Custom signals

enum Signal : string
{ ... }

@nogc Signal customSignal(string name) @safe pure nothrow
{
return cast(Signal)name;
}

I didn't know you could have an enum and extend it with a cast like this. Wow.


 * Signal composition

What happens when an unhandled signal is passed to a daemon?


 P.S. At the moment library doesn't support Mac and other Posix systems, the
 support is going to be added at next releases.

Do you foresee any difficulty in adapting this to Mac?


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread NCrashed via Digitalmars-d-announce

Thanks a lot for the respond!

Does the user sees/uses this name in any way afterwards? 
Because I
think you could also produce a unique string at compile-time 
(by using
__FILE__ and __LINE__, unless someone has a better idea), if 
the user
does not provide one. Maybe he just wants an anonymous daemon, 
or

doesn't care, whatever.
Yes, the name is used in windows service manager (you can 
start/stop the daemon by control panel) and for default locations 
of .pid and .lock files. Auto generated name will prevent sending 
signals and could be ugly displayed in service manager. The 
feature is useful for simple daemons, I will play around with 
that idea to find out if it worth.


If I understand correctly, the Daemon template waits for a list 
of (at
least one) Signal, then a delegate, then some more Signals, 
another

delegate, and so on?

If that's so I think you could ditch KeyValueList (or build it
invisibly to the user) and let the user write only the signals 
and

delegates:

alias daemon = Daemon!(
Signal.Terminate, Signal.Quit, Signal.Shutdown, Signal.Stop,
(logger, signal) {
...},
Signal.Hangup,
(logger) {
...}
...
);

Iterate the argument list, collecting Signals. When you hit a
delegate, create a Composition!( ... ) with the previous 
signals, jump

above the delegate and so on.
I will add the approach in next release (it requires some more 
additional templates to wrap all the mess) thanks to arguments 
grammar has no ambiguities.


Is the idea that, if the delegate has two arguments, then the 
second

is the signal that will be passed to it, and if it has only one
argument, only the logger will be passed?

Yes

What if the user does not want a logger? Is a daemon always 
associated

to a log file in OSes?
It is a general rule as the stderr and stdout files are closed. 
At next version I want to use duck typing for logger (or sink 
approach same as toString uses) and add a feature to reopen 
stderr/stdout to another file.



Is the main function always the last delegate?

Yes

Concerning the DaemonClient template, could you not ask for 
Daemon to

generate it on demand? Or is DaemonClient always used in another
module?
DaemonClient is designed to be used in another module, you can 
send signals with full Daemon template.



What happens when an unhandled signal is passed to a daemon?

The event is logged down and ignored.


Do you foresee any difficulty in adapting this to Mac?
All logic should be the same as for linux, I just don't have any 
machine to test

all out. I hope virtual machine will help.

On Sunday, 31 August 2014 at 16:01:10 UTC, Philippe Sigaud via 
Digitalmars-d-announce wrote:

Nice!

I have a few questions/remarks, mainly to simplify the API 
somewhat.

Please bear with me :-)


// First you need to describe your daemon via template
alias daemon = Daemon!(
DaemonizeExample1, // unique name


Does the user sees/uses this name in any way afterwards? 
Because I
think you could also produce a unique string at compile-time 
(by using
__FILE__ and __LINE__, unless someone has a better idea), if 
the user
does not provide one. Maybe he just wants an anonymous daemon, 
or

doesn't care, whatever.



// Setting associative map signal - callbacks
KeyValueList!(


If I understand correctly, the Daemon template waits for a list 
of (at
least one) Signal, then a delegate, then some more Signals, 
another

delegate, and so on?

If that's so I think you could ditch KeyValueList (or build it
invisibly to the user) and let the user write only the signals 
and

delegates:

alias daemon = Daemon!(
Signal.Terminate, Signal.Quit, Signal.Shutdown, Signal.Stop,
(logger, signal) {
...},
Signal.Hangup,
(logger) {
...}
...
);

Iterate the argument list, collecting Signals. When you hit a
delegate, create a Composition!( ... ) with the previous 
signals, jump

above the delegate and so on.

Is the idea that, if the delegate has two arguments, then the 
second

is the signal that will be passed to it, and if it has only one
argument, only the logger will be passed?

What if the user does not want a logger? Is a daemon always 
associated

to a log file in OSes?




// Main function where your code is
(logger, shouldExit) {
// will stop the daemon in 5 minutes
auto time = Clock.currSystemTick +
cast(TickDuration)5.dur!minutes;
while(!shouldExit()  time  Clock.currSystemTick) {  
}


return 0;
}


Is the main function always the last delegate?

Concerning the DaemonClient template, could you not ask for 
Daemon to

generate it on demand? Or is DaemonClient always used in another
module?

Because, given a Daemon, extracting the simplified DaemonClient 
can be

done, I think.



* Custom signals


enum Signal : string
{ ... }

@nogc Signal customSignal(string name) @safe pure nothrow
{
return cast(Signal)name;
}

I didn't know you could have an enum and extend it with a cast 
like this. Wow.




* 

Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread Philippe Sigaud via Digitalmars-d-announce
 Does the user sees/uses this name in any way afterwards? Because I
 think you could also produce a unique string at compile-time (by using
 __FILE__ and __LINE__, unless someone has a better idea), if the user
 does not provide one. Maybe he just wants an anonymous daemon, or
 doesn't care, whatever.

 Yes, the name is used in windows service manager (you can start/stop the
 daemon by control panel) and for default locations of .pid and .lock files.

OK.

 Auto generated name will prevent sending signals and could be ugly displayed
 in service manager. The feature is useful for simple daemons, I will play
 around with that idea to find out if it worth.

Great.


 I will add the approach in next release (it requires some more additional
 templates to wrap all the mess) thanks to arguments grammar has no
 ambiguities.

Yes, the grammar is simple, use it to simplify the life of your users.

 Is the idea that, if the delegate has two arguments, then the second
 is the signal that will be passed to it, and if it has only one
 argument, only the logger will be passed?

 Yes

OK.
IIRC, I read in your code that composed signals means the next
delegate must have the (logger, signal) {...} form.
Why?


 What if the user does not want a logger? Is a daemon always associated
 to a log file in OSes?

 It is a general rule as the stderr and stdout files are closed. At next
 version I want to use duck typing for logger (or sink approach same as
 toString uses) and add a feature to reopen stderr/stdout to another file.

OK.


 Concerning the DaemonClient template, could you not ask for Daemon to
 generate it on demand? Or is DaemonClient always used in another
 module?

 DaemonClient is designed to be used in another module, you can send signals
 with full Daemon template.

OK. I'd have thought that just having the name of the daemon would be
enough to send it signals.

 What happens when an unhandled signal is passed to a daemon?

 The event is logged down and ignored.

Is that the standard behavior for daemons in OSes?
You could have the daemon stopped, after logging the unhandled signal.
Or you could also block compilation if a daemon does not handle all signals...
Or have a 'catch-all' delegate, as std.concurrency.receive, which uses
a (Variant v) {...} delegate at the end.
See:
http://dlang.org/library/std/concurrency/receive.html

(btw, signals could also be types and you could have a handling syntax
similar to receive).


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread NCrashed via Digitalmars-d-announce

IIRC, I read in your code that composed signals means the next
delegate must have the (logger, signal) {...} form.
Why?
I can (not must) have the form, the delegate params are tested 
independently from signal composition.



Is that the standard behavior for daemons in OSes?

Most signals are simply ignored (except termination ones).

You could have the daemon stopped, after logging the unhandled 
signal.
Or you could also block compilation if a daemon does not handle 
all signals...
Some signals could be sent without any reason: sighup or 
interrogate in windows.
Ignoring most signals is a better strategy, the exception could 
be done for terminating signals - their default handlers should 
set `shouldExit` flag to true.


Or have a 'catch-all' delegate, as std.concurrency.receive, 
which uses

a (Variant v) {...} delegate at the end.
See:
http://dlang.org/library/std/concurrency/receive.html

Good idea, it will be implemented.

(btw, signals could also be types and you could have a handling 
syntax

similar to receive).
Ohh, that is much more complicated feature as it may seem. 
Signaling in both OSes are very limited. We need an additional 
channel to pass arbitrary memory between processes and also 
restrict data to be serializable. If I continue to move in that 
direction, the D will occasionally obtain a library for 
distributed cluster computing (like Cloud Haskell) ;).


On Sunday, 31 August 2014 at 19:45:32 UTC, Philippe Sigaud via 
Digitalmars-d-announce wrote:
Does the user sees/uses this name in any way afterwards? 
Because I
think you could also produce a unique string at compile-time 
(by using
__FILE__ and __LINE__, unless someone has a better idea), if 
the user
does not provide one. Maybe he just wants an anonymous 
daemon, or

doesn't care, whatever.


Yes, the name is used in windows service manager (you can 
start/stop the
daemon by control panel) and for default locations of .pid and 
.lock files.


OK.

Auto generated name will prevent sending signals and could be 
ugly displayed
in service manager. The feature is useful for simple daemons, 
I will play

around with that idea to find out if it worth.


Great.


I will add the approach in next release (it requires some more 
additional
templates to wrap all the mess) thanks to arguments grammar 
has no

ambiguities.


Yes, the grammar is simple, use it to simplify the life of your 
users.


Is the idea that, if the delegate has two arguments, then the 
second
is the signal that will be passed to it, and if it has only 
one

argument, only the logger will be passed?


Yes


OK.
IIRC, I read in your code that composed signals means the next
delegate must have the (logger, signal) {...} form.
Why?


What if the user does not want a logger? Is a daemon always 
associated

to a log file in OSes?


It is a general rule as the stderr and stdout files are 
closed. At next
version I want to use duck typing for logger (or sink approach 
same as
toString uses) and add a feature to reopen stderr/stdout to 
another file.


OK.


Concerning the DaemonClient template, could you not ask for 
Daemon to
generate it on demand? Or is DaemonClient always used in 
another

module?


DaemonClient is designed to be used in another module, you can 
send signals

with full Daemon template.


OK. I'd have thought that just having the name of the daemon 
would be

enough to send it signals.


What happens when an unhandled signal is passed to a daemon?


The event is logged down and ignored.


Is that the standard behavior for daemons in OSes?
You could have the daemon stopped, after logging the unhandled 
signal.
Or you could also block compilation if a daemon does not handle 
all signals...
Or have a 'catch-all' delegate, as std.concurrency.receive, 
which uses

a (Variant v) {...} delegate at the end.
See:
http://dlang.org/library/std/concurrency/receive.html

(btw, signals could also be types and you could have a handling 
syntax

similar to receive).




Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread Meta via Digitalmars-d-announce
On Sunday, 31 August 2014 at 16:01:10 UTC, Philippe Sigaud via 
Digitalmars-d-announce wrote:

* Custom signals


enum Signal : string
{ ... }

@nogc Signal customSignal(string name) @safe pure nothrow
{
return cast(Signal)name;
}

I didn't know you could have an enum and extend it with a cast 
like this. Wow.


This is not a good thing. Enums are supposed to denote a 
*closed*, enumerated set of items. It's fine here (but IMO bad 
style) because the author expects there to be user-created values 
casted to Signal passed to functions/templates that expect a 
Signal, but this would wreak havoc on code that was expecting a 
valid enum value (by valid, I mean only one of the predefined 
enum values).


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread Philippe Sigaud via Digitalmars-d-announce
On Sun, Aug 31, 2014 at 11:36 PM, Meta via Digitalmars-d-announce
digitalmars-d-announce@puremagic.com wrote:
 I didn't know you could have an enum and extend it with a cast like this.

 This is not a good thing. Enums are supposed to denote a *closed*,
 enumerated set of items.

I agree.

 It's fine here (but IMO bad style) because the
 author expects there to be user-created values casted to Signal passed to
 functions/templates that expect a Signal, but this would wreak havoc on code
 that was expecting a valid enum value (by valid, I mean only one of the
 predefined enum values).

I was about to suggest final switch, until I saw this extension of
Signal. I wonder what happens to final switch in this case.


Re: Daemonize v0.1 - simple way to create cross-platform daemons

2014-08-31 Thread Philippe Sigaud via Digitalmars-d-announce
 I can (not must) have the form, the delegate params are tested independently
 from signal composition.

OK, good.

 Is that the standard behavior for daemons in OSes?

 Most signals are simply ignored (except termination ones).

I see.

 Some signals could be sent without any reason: sighup or interrogate in
 windows.
 Ignoring most signals is a better strategy, the exception could be done for
 terminating signals - their default handlers should set `shouldExit` flag to
 true.

OK, I didn't know that.

 http://dlang.org/library/std/concurrency/receive.html

 Good idea, it will be implemented.

Great!