An open API service indexing awesome lists of open source software.

https://github.com/qntfrd/applife

♻️ Handle the lifecyle of your application
https://github.com/qntfrd/applife

Last synced: about 2 months ago
JSON representation

♻️ Handle the lifecyle of your application

Awesome Lists containing this project

README

        

# AppLife

♻️ Handle the lifecyle of your application

[![codecov](https://codecov.io/gh/qntfrd/applife/branch/main/graph/badge.svg?token=mRxtORoSO3)](https://codecov.io/gh/qntfrd/applife)

## Getting started

```ts
import AL from "applife"

const app = new AL({
// first load your environment
config: { up: loadenv },

// when config is done, open pg connection
pg: {
needs: ["config"], // wait for config to have run
up: async ({ config }) => { // each steps receive the full context
const client = new Client();
await client.connect();
return client
},
down: ({ pg }) => pg.close(), // here pg is what was instanciated in `up`
after: "start" // will only close pg AFTER the up stage has been downed
},

http: {
needs: ["config"],
up: ({ config }) => new Koa().use(/* ... */),
},

socket: {
needs: ["http"],
up: ({ http, pg }) => new Server(require("http").createServer(http.callback()))
},

start: {
needs: ["pg", "http", "socket"],
up: ({ http, config }) => http.listen(port),
down: ({ start }) => up.close()
}
})

app.on("stopped", signal => console.log(`App stopped because ${signal} was received`))
app.start()
.then(({ config }) => console.log(`App started on port ${config.port}`))
.catch(e => console.error("Could not start app", e))
```

This will start the `config` stage, then the `pg` and `http` stages, then the
`socket` stage and finally if the `start` stage.

If your app receive `SIGINT`, `SIGTERM`, `unhandledRejection` or `uncaughtException`,
(or if you call `app.close()`), `start` will be downed first then `pg`.

## API

### `AppLife#constructor(dependencies)`

Setup the the applife and load dependencies

- `T extends {[key: string]: unknown}` is the object that represent your state,
once fully loaded.

`T` can be infered from usage.
For example if you have:

```ts
const app = new Applife({
a: { up: () => Promise.resolve("A") },
b: { up: () => Promise.resolve(42) },
})
// T: { a: string, b: number }
```

- `dependencies: {[key: keyof T]: dependency}`, an object that represent the list
of dependencies. The key is important as each dependency will receive `Pick`

- `dependency` is an object with the following keys

- `needs?: keyof T | Array`: an optional array of steps which must
resolve BEFORE calling the `up` method

- `up?: (loaded: Pick) => Promise`: the function to boot the current stage (once all in `needs` resolved).
This function takes all loaded properties and MUST return a promise.
`up` is optional because you may only want to specify a shutdown step.

- `after?: keyof T | Array`: an optional array of steps which must
resolve BEFORE calling the `down` method

- `down?: (loaded: Pick) => Promise`: The function
to call to gracefully shutdown this step.
This function will only be called AFTER all steps defined in `after`.
This MUST return a promise

### `AppLife.start() => Promise`

Starts your application (run all the `up` functions) and returns loaded values.

If any dependency fails to load, `start` will throw a `Boot sequence failed` with
a list of all errors that were caught in `Error.details: Error[]`
The throw will occur AFTER all dependencies are successfuly unloaded

`start` will return your resolved dependencies

### `AppLife.stop() => Promise`

Stop your application (run all the `down` functions).

`stop` will only stop a dependency that was started.

### `AppLife.run() => Promise`

Treat your application as if it were a one of application.

Basically is `app.start().then(() => app.stop())`

Handles dependencies error the same way `start` would.

### `emit stopped(reason)`

After the app stops, it emits the `stopped` event with one of the following reasons:
- `SIGTERM` received the `SIGTERM` signal
- `SIGINT` received the `SIGINT` signal
- `uncaughtException` an exception was not handled by your code
- `unhandledRejection` a promise rejection was not handled by your code
- `stop` - if the `stop` method was called