Git Product home page Git Product logo

service's Introduction

ContainerSSH - Launch Containers on Demand

ContainerSSH Service Library

⚠⚠⚠ Deprecated: ⚠⚠⚠
This repository is deprecated in favor of libcontainerssh for ContainerSSH 0.5.

This library provides a common way to manage multiple independent services in a single binary.

Creating a service

In order to create a service you must implement the Service interface:

type Service interface {
	// String returns the name of the service
	String() string

	RunWithLifecycle(lifecycle Lifecycle) error
}

The Run function gets passed a Lifecycle object. It must call the appropriate lifecycle hooks:

func (s *myService) RunWithLifecycle(lifecycle Lifecycle) error {
    //Do initialization here
    lifecycle.Running()
    for {
        // Do something
        if err != nil {
            return err
        }
        if lifecycle.ShouldStop() {
            shutdownContext := lifecycle.Stopping()
            // Handle graceful shutdown.
            // If shutdownContext expires, shut down immediately.
            // Then exit out of the loop.
            break
        }
    }
    return nil
}

For advanced use cases you can replace the lifecycle.ShouldStop() call with fetching the context directly using lifecycle.Context(). You can then use the context in a select statement.

Warning! Do not call RunWithLifecycle() on the service directly. Instead, always call Run() on the lifecycle to enable accurate state tracking and error handling.

Creating a lifecycle

In order to run a service you need to create a Lifecycle object. Since Lifecycle is an interface you can implement it yourself, or you can use the default implementation:

lifecycle := service.NewLifecycle(service)

The service parameter should be the associated service. The lifecycle can be used to add hooks to the service. Calling these functions multiple times is supported, but the call order of hook functions is not guaranteed.

lifecycle.OnStateChange(func(s service.Service, l service.Lifecycle, newState service.State) {
    // do something
})
lifecycle.OnStarting(func(s service.Service, l service.Lifecycle) {
    // do something
})
lifecycle.OnRunning(func(s service.Service, l service.Lifecycle) {
    // do something
})
lifecycle.OnStopping(func(s service.Service, l service.Lifecycle, shutdownContext context.Context) {
    // do something
})
lifecycle.OnStopped(func(s service.Service, l service.Lifecycle) {
    // do something
})
lifecycle.OnCrashed(func(s service.Service, l service.Lifecycle, err error) {
    // do something
})

These hook functions can also be chained:

lifecycle.OnStarting(myHandler).OnRunning(myHandler)

You can now use the Lifecycle to run the service:

err := lifecycle.Run()

Warning! Do not call RunWithLifecycle() on the service directly. Instead, always call Run() on the lifecycle to enable accurate state tracking and error handling.

Using the service pool

One of the advanced components in this library is the Pool object. It provides an overlay for managing multiple services in parallel, and it implements the Service interface itself. In other words, it can be nested.

First, let's create a pool:

pool := service.NewPool(
    service.NewLifecycleFactory(),
    logger,
)

The logger variable is a logger from the log package. You can then add subservices to the pool. When adding a service the pool will return the lifecycle object you can use to add hooks. The hook functions can be chained for easier configuration:

_ = pool.
    Add(myService1).
    OnRunning(func (s Service, l Lifecycle) {
        log.Printf("%s is now %s", s.String(), l.State())
    })

Once the services are added the pool can be launched:

lifecycle := service.NewLifecycle(pool)
go func() {
    err := lifecycle.Run()
    // Handle errors here
}
lifecycle.Shutdown(context.Background())

Ideally, the pool can be used to handle Ctrl+C and SIGTERM events:

signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
go func() {
    if _, ok := <-signals; ok {
        // ok means the channel wasn't closed
        lifecycle.Shutdown(
            context.WithTimeout(
                context.Background(),
                20 * time.Second,
            )
        )
    }
}()
// Wait for the pool to terminate.
lifecycle.Wait()
// We are already shutting down, ignore further signals
signal.Ignore(syscall.SIGINT, syscall.SIGTERM)
// close signals channel so the signal handler gets terminated
close(signals)

service's People

Contributors

dependabot[bot] avatar janosdebugs avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.