--- The dependency handling in supervision-scripts is meant to be used in installations that don't have access to it. Put another way, it's a "Poor Man's Solution" to the problem and functions as a convenience. The feature is turned off by default, and this will cause any service definition that requires other services to run-loop repeatedly until someone starts them manually. This could be said to be the default behavior of most installations that don't have dependency handling, so I'm not introducing a disruptive behavior with this feature. Why --- I could have hard-coded many of the dependencies into the various run scripts, but this would have created a number of problems for other areas. 1. Hard-coding prevents switching from shell to execline in the future, by necessitating a re-write. There will be an estimated 1,000+ scripts when the project is complete, so this is a major concern. 2. We are already using the filesystem as an ad-hoc database, so it makes sense to continue with this concept. The dependencies should be stored on the filesystem and not inside of the script. With this in mind, I picked sv/(service)/needs as a directory to hold the definitions to be used. Because I can't envision what every init and future dependency management framework would look like, I'll simply make it as generic as I can, leaving things as open as possible to additional changes. A side note: it is by fortuitous circumstance that anopa uses a ./needs directory that has the same functionality and behavior. I use soft links "just because". Anopa uses named files. The net effect is the same. Each dependency is simply a named soft link that points to a service that needs to be started, typically something like "sv/(service)/needs/foobar points to /service/foobar". In this case, a soft link is made with the name of the service, pointing to the service definition in /service. This also allows me to ensure that the dependency is actually available, and not just assume that it is there. A single rule determines what goes into ./needs, "you can only have the names of other services that are explicitly needed". You can say "foo needs baz" and "baz needs bar" but NEVER would you say "foo needs baz, foo needs bar". This is intentional because it's not the job of the starting service to handle the entire chain. It simplifies the list of dependencies because a service will only worry about its immediate needs, and not the needs of dependent services it launches. It also has the desirable property of making dependency chains self-organizing, which is an important decision with hundreds of services having potentially hundreds of dependencies. Setup is straightforward and you can easily extend a service need by adding one soft link to the new dependency. This also fits with my current use of a single launch script; I don't have to change the script, just the parameters that the script uses. The new soft link becomes just another parameter. You could call this "peer-level dependency resolution" if you like. How --- Enabling this behavior requires that you set sv/.env/NEEDS_ENABLED to the single character "1". It is normally set to "0". With the setting disabled (zero), the entire set of code for dependency handling is simply ignored; it is inside of a large if-then wrapper that looks at this flag and skips over it when needed. When the setting is enabled (one), the code will trigger. There has been discussion elsewhere about re-writing this code, and while I like the idea of cleaning it up, for the time being, it is functional as-is. The script is meant to walk through a list of services in no order, asking each service to start, and once started ensuring that it is indeed running by calling its ./check script (if it has one). Should a requested service fail to start, a log entry is issued with the name of the offending service, and the ./run script is aborted, leading to a run-loop. On the next loop, the service start will quickly succeed for all of the services that are already running, which causes the script to rapidly advance to the one service that had the issue. Note that, because the same launch script is used for both the original service and its dependency, it is possible for the dependency to start its own dependencies. This is essentially a self-organizing recursive decent. Once all of the needs are started, the behavior is the same as if dependency handling is disabled; a run directory is created if needed, and the process launched. I don't attempt to shut down any dependent services because of the complexity involved. While I'm sure I could write some kind of reverse-tree-walking script, it's just not something easily done in shell. The behavior of "service goes down but dependencies stay up" is not ideal, but keep in mind, this is an optional feature of last resort, a freebie. You get what you pay for sometimes. :) Experiences ---------- I am currently using this feature on my home server, and it works fine. I have yet to have it fail to start a dependency chain, unless I am testing a definition and the settings were bad to begin with. Start up time for a test chain, forked-daapd>avahi-daemon>dbus, is very quick on a single core Sempron 140, less than a second, so I don't see speed being an issue. Disabling the feature brings back the "old behavior" and forked-daapd will not start until you manually start dbus and avahi-daemon. If you have questions I'll try to answer them. Hopefully I've adequately covered the design decisions and the net effect of them. Otherwise, that's my 0.05 cents on my experiences with dependency management.Received on Wed Apr 29 2015 - 16:46:39 UTC
This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:44:19 UTC