All Projects → damianh → LittleForker

damianh / LittleForker

Licence: Apache-2.0 license
A .NET utility library to spawn, supervise and (optionally) cleanly shut down child processes.

Programming Languages

C#
18002 projects

Projects that are alternatives of or similar to LittleForker

Pluralize.NET
📘 Pluralize or singularize any English word.
Stars: ✭ 50 (-51.46%)
Mutual labels:  dotnet-standard
NetCoreForce
Salesforce REST API toolkit for .NET Standard and .NET Core
Stars: ✭ 77 (-25.24%)
Mutual labels:  dotnet-standard
AnyDiff
A CSharp (C#) diff library that allows you to diff two objects and get a list of the differences back.
Stars: ✭ 80 (-22.33%)
Mutual labels:  dotnet-standard
RESTCountries.NET
.NET Standard wrapper library around the API provided by REST Countries https://restcountries.com. The world in .NET 🔥.
Stars: ✭ 33 (-67.96%)
Mutual labels:  dotnet-standard
covidtrackerapiwrapper
CovidSharp is a crossplatform C# API wrapper for the Coronavirus tracking API (https://github.com/ExpDev07/coronavirus-tracker-api)
Stars: ✭ 11 (-89.32%)
Mutual labels:  dotnet-standard
ShippingRates
.NET wrapper to UPS, FedEx, USPS and DHL shipping rates APIs
Stars: ✭ 23 (-77.67%)
Mutual labels:  dotnet-standard
B2.NET
.NET library for Backblaze's B2 Cloud Storage
Stars: ✭ 63 (-38.83%)
Mutual labels:  dotnet-standard
elgamalext
Extension for the .NET Framework cryptography subsystem, which introduces the ElGamal public key cryptosystem with support for homomorphic multiplication.
Stars: ✭ 14 (-86.41%)
Mutual labels:  dotnet-standard
MarkEmbling.PostcodesIO
.NET library for interacting with the excellent Postcodes.io service.
Stars: ✭ 22 (-78.64%)
Mutual labels:  dotnet-standard
Nager.VideoStream
Get images from a network camera stream or webcam
Stars: ✭ 27 (-73.79%)
Mutual labels:  dotnet-standard
Merkurius
Portable Deep Learning Library for .NET
Stars: ✭ 1 (-99.03%)
Mutual labels:  dotnet-standard
NwRfcNet
An easy way of making SAP RFC calls from .NET Core
Stars: ✭ 83 (-19.42%)
Mutual labels:  dotnet-standard
ReflectionToIL
A demonstration and benchmark of different approaches to load closure fields using reflection and dynamic code generation
Stars: ✭ 30 (-70.87%)
Mutual labels:  dotnet-standard
LiteNetwork
A simple and fast .NET networking library compatible with .NET Standard 2, .NET 5, 6 and 7.
Stars: ✭ 66 (-35.92%)
Mutual labels:  dotnet-standard
Disboard
Collection of fediverse client libraries
Stars: ✭ 13 (-87.38%)
Mutual labels:  dotnet-standard
Capstone.NET
.NET Core and .NET Framework binding for the Capstone Disassembly Framework
Stars: ✭ 108 (+4.85%)
Mutual labels:  dotnet-standard
HULK-v3
Asynchronous HTTP Botnet for Distributed Denial of Service (DDoS)
Stars: ✭ 152 (+47.57%)
Mutual labels:  named-pipes
parity-tokio-ipc
Parity tokio-ipc
Stars: ✭ 54 (-47.57%)
Mutual labels:  named-pipes
not-enough-standards
A modern header-only C++ library that provides platform-independent utilities.
Stars: ✭ 197 (+91.26%)
Mutual labels:  named-pipes
FtpServer
An FTP server program for .NET Core, and its customizable .NET Standard core library
Stars: ✭ 28 (-72.82%)
Mutual labels:  dotnet-standard

Little Forker

CI NuGet feedz.io

A utility to aid in the launching and supervision of processes. The original use case is installing a single service who then spawns other processes as part of a multi-process application.

Features

  1. ProcessExitedHelper: a helper around Process.Exited with some additional logging and event raising if the process has already exited or not found.

  2. ProcessSupervisor: allows a parent process to launch a child process and lifecycle is represented as a state machine. Supervisors can participate in co-operative shutdown if supported by the child process.

  3. CooperativeShutdown: allows a process to listen for a shutdown signal over a NamedPipe for a parent process to instruct a process to shutdown.

Installation

dotnet add package LittleForker

CI packages are on personal feed: https://www.myget.org/F/dh/api/v3/index.json

Using

1. ProcessExitedHelper

This helper is typically used by "child" processes to monitor a "parent" process so that it exits itself when the parent exits. It's also safe guard in co-operative shut down if the parent failed to signal correctly (i.e. it crashed).

It wraps Process.Exited with some additional behaviour:

  • Raises the event if the process is not found.
  • Raises the event if the process has already exited which would otherwise result in an InvalidOperationException
  • Logging.

This is something simple to implement in your own code so you may consider copying it if you don't want a dependency on LittleForker.

Typically you will tell a process to monitor another process by passing in the other process's Id as a command line argument. Something like:

.\MyApp --ParentProcessID=12345

Here we extract the CLI arg using Microsoft.Extensions.Configuration, watch for a parent to exit and exit ourselves when that happens.

var configRoot = new ConfigurationBuilder()
   .AddCommandLine(args)
   .Build();

var parentPid = _configRoot.GetValue<int>("ParentProcessId");
using(new ProcessExitedHelper(parentPid, exitedHelper => Environment.Exit(0)))
{
   // Rest of application
}

Environment.Exit(0) is quite an abrupt way to shut town; you may want to handle things more gracefully such as flush data, cancel requests in flight etc. For an example, see NotTerminatingProcess Run() that uses a CancellationTokenSource.

2. ProcessSupervisor

Process supervisor launches a process and tracks it's lifecycle that is represented by a state machine. Typically use case is a "parent" processes launching one or more "child" processes.

There are two types of processes that are supported:

  1. Self-Terminating where the process will exit of it's own accord.
  2. Non-Terminating is a process that never shut down unless it is signalled to do so (if it participates in co-operative shutdown) or is killed.

A process's state is represented by ProcessSupervisor.State enum:

  • NotStarted,
  • Running,
  • StartFailed,
  • Stopping,
  • ExitedSuccessfully,
  • ExitedWithError,
  • ExitedUnexpectedly,
  • ExitedKilled

... with the transitions between them described with this state machine depending whether self-terminating or non-terminating:

statemachine

Typically, you will want to launch a process and wait until it is in a specific state before continuing (or handle errors).

// create the supervisor
var supervisor = new ProcessSupervisor(
   processRunType: ProcessRunType.NonTerminating, // Expected to be a process that doesn't stop
   workingDirectory: Environment.CurrentDirectory,
   processPath: "dotnet",
   arguments: "./LongRunningProcess/LongRunningProcess.dll");

// attach to events
supervisor.StateChanged += state => { /* handle state changes */ };
supervisor.OutputDataReceived += s => { /* console output */ }

// start the supervisor which will launch the process
await supervisor.Start();

// ... some time later
// attempts a co-operative shutdown with a timeout of 3
// seconds otherwise kills the process

await supervisor.Stop(TimeSpan.FromSeconds(3));

With an async extension, it is possible to await a supervisor state:

var exitedSuccessfully = supervisor.WhenStateIs(ProcessSupervisor.State.ExitedSuccessfully);
await supervisor.Start();
await Task.WhenAny(exitedSuccessfully).

You can also leverage tasks to combine waiting for various expected states:

var startFailed = supervisor.WhenStateIs(ProcessSupervisor.State.StartFailed);
var exitedSuccessfully = supervisor.WhenStateIs(ProcessSupervisor.State.ExitedSuccessfully);
var exitedWithError = supervisor.WhenStateIs(ProcessSupervisor.State.ExitedWithError);

supervisor.Start();

var result = await Task.WhenAny(startFailed, exitedSuccessfully, exitedWithError);
if(result == startFailed)
{
   Log.Error(supervisor.OnStartException, $"Process start failed {supervisor.OnStartException.Message}")
}
// etc.

CooperativeShutdown

Cooperative shutdown allows a "parent" process to instruct a "child" process to shut down. Different to SIGTERM and Process.Kill() in that it allows a child to acknowledge receipt of the request and shut down cleanly (and fast!). Combined with Supervisor.Stop() a parent can send the signal and then wait for ExitedSuccessfully.

The inter-process communication is done via named pipes where the pipe name is of the format LittleForker-{processId}

For a "child" process to be able receive co-operative shut down requests it uses CooperativeShutdown.Listen() to listen on a named pipe. Handling signals should be fast operations and are typically implemented by signalling to another mechanism to start cleanly shutting down:

var shutdown = new CancellationTokenSource();
using(await CooperativeShutdown.Listen(() => shutdown.Cancel())
{
   // rest of application checks shutdown token for co-operative
   // cancellation. See MSDN for details.
}

For a "parent" process to be able to signal:

await CooperativeShutdown.SignalExit(childProcessId);

This is used in ProcessSupervisor so if your parent process is using that, then you typically won't be using this explicitly.

Building

With docker which is same as CI:

  • Run build.cmd/build.sh to compile, run tests and build package.

Local build which requires .NET Core SDKs 2.1, 3.1 and .NET 5.0:

  • Run build-local.cmd/build-local.sh to compile, run tests and build package.

Credits & Feedback

@randompunter for feedback.

Hat tip to @markrendle for the project name.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].