@startier/ohrid v1.1.0
@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 wheretscoutputs the.jsfiles.
{
"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-serviceModify 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-serviceFile 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 thedoFlagsWorksetting 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 thenewcommand generate.tsfiles, defaults totrueif"typescript"is adependencyordevDependencyinpackage.jsondriver: 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 dockerdocker.from: the source image used for the generatedDockerfiledocker.script: thenpm runscript used in the build step in theDockerfiledocker.image: the image used bydocker-compose.yml, will generate a script called./build-image.shthat runsdockerwith the correct arguments if set, otherwise the correct arguments will be passed to thedocker-compose.ymldirectly
exports: sets the export style for code generated by thenewcommandservices: 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.ymlfileservices[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.jsonfiles to import services and methods fromexport: the methods that should be exported for importing usingimportin otherservices.jsonfiles
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 totrueremoteCall: 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 aClientneeds 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 aMethodneeds 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.exitbeing 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>