@startier/ohrid
v1.1.0
Published
A library for managing distributed nodes
Downloads
9
Readme
@startier/ohrid
A library for managing distributed nodes.
How does it work?
You may define Services, Methods and Entrypoints.
Services may contain Methods and Entrypoints.
Services can be started, creating a Node.
Methods can be invoked by Nodes.
Nodes automatically execute Entrypoints if any are present.
When a Node invokes a Method:
- If the Node and the Method are in the same Service, the Method gets run on the same Node that invoked it.
- If the Node and the Method are in a different Service, a Remote call is made.
Remote calls are handled by communication Drivers.
[!NOTE] Features like
network connections
,server / client handling
,load balancing
, etc... are not defined by the library and their handling is entierly up to the driver, if you need a fully-featured driver you can use@startier/ohrid-jsonrpc-driver
.
Usage
- Install the package using
npm
(or anything compatible):
npm install @startier/ohrid
- Read the output of the help command:
npx ohrid help
- Install a communication driver (for example:
@startier/ohrid-local-driver
) and initialize the project:
npm install @startier/ohrid-local-driver
npx ohrid init --driver=@startier/ohrid-local-driver
- Optional Edit the base path in
services.json
:
[!NOTE]
This is required when you use TypeScript and the path should be set to wheretsc
outputs the.js
files.
{
"path": "dist"
}
- Optional Create a service (or a couple of them):
[!NOTE]
This is recommended when you are using a non-trivial driver that needs configuration.
npx ohrid new service my-service --entrypoint=my-service-entrypoint
- Create a method (or a couple of them):
npx ohrid new method my-method --service=my-service
Modify your methods and services (see the API reference section for more info)
Run a service (you can run a service without creating a config for it, it will inherit the default config)
[!NOTE]
A service without an entrypoint will run forever (or until the driver decides to exit).
npx ohrid start my-service
File Structure
./services.json
: the configuration file./package.json
: npm/node package file./rpc/
: RPC method directory./*/index.[ts|js]
: RPC method
./src/
: entrypoint directory./**/*/*.[ts|js]
: entrypoint
./drivers/
: communication driver directory./*/index.[ts|js]
: communication driver
Configuration
[!WARNING] Any flag that isn't explicitly defined by a command overrides this configuration (ex:
--services.test.settings.doFlagsWork=
would override thedoFlagsWork
setting on the servicetest
.)
The configuration follows the following schema:
{
path?: string;
typescript?: boolean;
driver?: ServiceConfig["driver"];
settings?: ServiceConfig["settings"];
docker?: DockerConfig;
exports?: "named" | "default";
services?: Record<string, ServiceConfig>;
import?: string[];
export?: string[];
}
ServiceConfig = {
entrypoint?: string;
amount?: number;
settings?: Record<string, object | string | number | boolean>;
driver?: string;
}
DockerConfig = {
from?: string;
script?: string;
image?: string;
}
path
: location of compiled JavaScript files, defaults to"."
typescript
: should thenew
command generate.ts
files, defaults totrue
if"typescript"
is adependency
ordevDependency
inpackage.json
driver
: the default communication driver that will be used if no driver is specified for a servicesettings
: the default service settings that get merged with the service settings (defined by external libraries, drivers, etc..)docker
: configuration used bynpx ohrid generate docker
docker.from
: the source image used for the generatedDockerfile
docker.script
: thenpm run
script used in the build step in theDockerfile
docker.image
: the image used bydocker-compose.yml
, will generate a script called./build-image.sh
that runsdocker
with the correct arguments if set, otherwise the correct arguments will be passed to thedocker-compose.yml
directly
exports
: sets the export style for code generated by thenew
commandservices
: service configurationservices[name].entrypoint
: the file that gets run when the service starts, otherwise the service will run forever and only execute methods when requestedservices[name].amount
: how many copies of the service should get added to thedocker-compose.yml
fileservices[name].settings
: service settings for external libraries or driversservices[name].driver
: the communication driver used by the service
import
: sub-directories and packages where there are otherservices.json
files to import services and methods fromexport
: the methods that should be exported for importing usingimport
in otherservices.json
files
API Reference
@startier/ohrid
Log
A function type that is used to print information to the console.
Signature:
function Log(
type: "info" | "output" | "error" | "debug" | "warning",
message: string
): void;
Context
An object that is used for communication between nodes.
This is used by communication drivers to provide a transport layer to ohrid
.
Properties:
log: Log
: the default logger passed down by the creator of the driverexit: boolean
: an observed value that will stop the node when set totrue
remoteCall: function
: a function that gets called when the node invokes a method from an other service- Signature:
function remoteCall<TService extends string, TParams extends any[], TReturn>(
method: Method<TService, TParams, TReturn>,
...params: TParams
): Promise<Awaited<TReturn>>;
Driver
A communication driver for handling remote calls.
Properties
createNode: function
: a function that gets called when a context for a node needs to be created- Signature:
function createNode(
name: string,
config: ServiceConfig,
rpcMethods: Record<string, Method>,
log: Log
): Context;
handleDockerCompose: function
: a function that gets called when a service uses this driver and needs to generate adocker-compose.yml
- Signature:
function handleDockerCompose(item: {
service: ServiceConfig;
dockerServiceName: string;
appendLine: (text: string): void;
block: (cb: (): Promise<void>): Promise<void>;
store: Record<string, string | undefined>;
}): Promise<void>;
getDockerfileExtensions: function
: a function that gets called when a service uses this driver and needs to generate aDockerfile
- Signature:
function getDockerfileExtensions(
place:
| "beforeDeps"
| "afterDeps"
| "beforeBuild"
| "afterBuild"
| "beforeRunner"
| "afterRunner",
serviceConfigs: Record<string, ServiceConfig> | undefined
): string;
Method<TService extends string, TParams extends any[], TReturn>
An invocable method returned by declareMethod()
.
Properties
createCaller: function
: a function that gets called when aClient
needs to invoke a method locally.- Signature:
function createCaller(
context: Context
): (...params: TParams): Promise<Awaited<TReturn>>;
service: TService
: the service's name that is allowed to run this methodname: string
: the method's unique name
Client
An abstraction over Context
that is used by methods and entrypoints.
Properties
invoke: function
: this function should be called when aMethod
needs to be invoked- Signature:
function invoke<TService extends string, TParams extends any[], TReturn>(
method:
| Method<TService, TParams, TReturn>
| Promise<{ default: Method<TService, TParams, TReturn> }>,
...params: TParams
): Promise<Awaited<TReturn>>;
waitForExit: function
: this function returns a promise that resolves when the node finishes with operation (or due toContext.exit
being set totrue
)- Signature:
function waitForExit(): Promise<void>;
log: Log
: the default logger passed by the driver
client
A function that can wrap a Context
into a Client
.
Signature:
function client(context: Context): Client;
declareMethod
Wrap a function and service name into a Method
to be used as a default export of a RPC method.
Makes the function be remote-callable by nodes that aren't the correct service when invoked using Client.invoke()
.
Signature:
function declareMethod<TService extends string, TParams extends any[], TReturn>(
service: TService,
method: (context: Client, ...params: TParams): TReturn
): Method<TService, TParams, TReturn>;
@startier/ohrid/service
runService
Runs a service Context
with an optional entrypoint.
This command is equivalent to how the command npx ohrid start <service>
, but the driver and the context must be created manually.
Signature:
function runService(
context: Context,
entrypoint?: (client: Client): Promise<boolean | void>
): Promise<void>