Skip to content

Application (StrataService)

The StrataService class is the top-level object for a Strata service. It holds configuration, manages the backend connection, coordinates contexts, runs global middleware, and listens for incoming requests.

For conceptual background, see Architecture.

typescript
import { StrataService } from '@strata-js/strata';

Constructor

typescript
new StrataService(config : StrataServiceConfig)

Creates a new service instance. The config is the only argument.

typescript
const service = new StrataService({
    service: {
        serviceGroup: 'UserService',
        concurrency: 32,
    },
    backend: {
        type: 'redis-streams',
        redis: { host: 'localhost', port: 6379 },
    },
});

See StrataServiceConfig for the full configuration shape.

Properties

PropertyTypeDescription
idstringAuto-generated unique ID for this service instance.
namestringApplication name (from package.json or APP_NAME env).
displayNamestringHuman-friendly version of name (via lodash startCase).
serviceGroupstringThe service group this instance belongs to.
versionstringApplication version (from package.json or APP_VERSION).
concurrencynumberMax concurrent requests this instance will process.
initializedbooleantrue after start() has been called.
configStrataServiceConfigThe config object passed to the constructor.
infoServiceInfoSnapshot of the service's current state. See below.
contextsRecord<string, string[]>Map of registered context names to their operation names.
backendsstring[]List of registered backend names.
middlewareSet<OperationMiddleware>Set of globally registered middleware.
outstandingRequestsMap<string, StrataRequest>Currently in-flight requests.
lastBusy{ time: Date, lag: number }Last time node-toobusy detected event loop lag.

Methods

start()

typescript
service.start() : Promise<void>

Initializes the backend, enables service discovery (unless disabled in config), and starts listening for incoming requests and commands. Call this after registering all contexts and middleware.

Throws AlreadyInitializedError if called more than once.

typescript
// Register everything first
service.registerContext(usersContext);
service.useMiddleware(authMiddleware);

// Then start
await service.start();

registerContext()

Registers a context with the service. Has two overloads:

typescript
// Use the context's own name (set in constructor)
service.registerContext(context : StrataContext) : void

// Override the name
service.registerContext(name : string, context : StrataContext) : void

If the context doesn't have a name and none is provided, it throws. If the name is already registered, it throws AlreadyRegisteredError.

typescript
import { StrataContext } from '@strata-js/strata';

const users = new StrataContext('users');
users.registerOperation('get', async (request) =>
{
    return { user: await db.findUser(request.payload.userId) };
});

// These are equivalent:
service.registerContext(users);
service.registerContext('users', users);

getContext()

typescript
service.getContext(contextName : string) : StrataContext

Retrieves a registered context by name. Throws UnknownContextError if not found.

useMiddleware()

typescript
service.useMiddleware(middleware : OperationMiddleware | OperationMiddleware[]) : void

Registers global middleware that runs on every request across all contexts. Accepts a single middleware or an array.

For details on how middleware ordering works, see Middleware Model.

typescript
service.useMiddleware(new AuthMiddleware());
service.useMiddleware([ new LoggingMiddleware(), new TimingMiddleware() ]);

registerBackend()

typescript
service.registerBackend(name : string, backendClass : BackendConstructor) : void

Registers a custom backend constructor under the given name. Once registered, the name can be used as the type in the backend config. Throws if the name is already registered. See Using a Custom Backend for a full walkthrough.

typescript
import { MyCustomBackend } from './backends/custom.js';

service.registerBackend('custom', MyCustomBackend);

getBackend()

typescript
service.getBackend<T extends BaseStrataBackend>(name : string) : T

Returns the backend instance registered under the given name.

setConcurrency()

typescript
service.setConcurrency(concurrency : number) : void

Updates the max concurrent requests at runtime.

setTooBusy()

typescript
service.setTooBusy(options : TooBusyConfig) : void

Updates node-toobusy options at runtime. See TooBusyConfig.

registerTeardown()

typescript
service.registerTeardown(fn : () => Promise<void>) : void

Registers a cleanup function that will be called during service shutdown. Use this for closing database connections, flushing buffers, or any other teardown logic.

typescript
service.registerTeardown(async () =>
{
    await database.disconnect();
});

Built-in service Context

Every StrataService automatically registers a service context with a single info operation. This is useful for health checks, debugging, and service discovery.

info Operation

Send a request to service/info with an empty payload. The response is a ServiceInfo object:

typescript
// From a client
const response = await client.request('UserService', 'service', 'info', {});

Example response payload:

json
{
    "id": "l7aNdfrRDZW8nt0FBaSS",
    "serviceName": "User Service",
    "serviceGroup": "UserService",
    "version": "1.2.0",
    "strataVersion": "2.0.0",
    "environment": "production",
    "concurrency": 32,
    "outstanding": 3,
    "hostname": "worker-01",
    "lastBusy": {
        "time": "2024-06-25T16:16:40.794Z",
        "lag": 0
    },
    "contexts": {
        "service": [ "info" ],
        "users": [ "get", "create", "delete" ]
    },
    "backend": {
        "type": "redis-streams"
    }
}

INFO

The info operation responds from whichever service instance picks up the request. If you need info from a specific instance, use the info command via client.command() instead.

Configuration Reference

StrataServiceConfig

typescript
interface StrataServiceConfig
{
    service : ServiceConfig;
    backend : BackendConfig;
    logging ?: LoggerConfig;
    client ?: ClientConfig;
    aliases ?: Record<string, string>;
    interruptsToForceShutdown ?: number;
    shutdownTimeout ?: number;
}

ServiceConfig

typescript
interface ServiceConfig
{
    serviceGroup : string;
    concurrency ?: number;              // Default: 32
    defaultRequestTimeout ?: number;
    toobusy ?: TooBusyConfig;
}

TooBusyConfig

Options for node-toobusy dynamic concurrency control:

typescript
interface TooBusyConfig
{
    maxLag ?: number;
    interval ?: number;
    smoothingFactorOnRise ?: number;
    smoothingFactorOnFall ?: number;
}

BackendConfig

typescript
interface BackendConfig
{
    type : string;
    discovery ?: DiscoveryConfig;
    validateEnvelopes ?: boolean;
    [key : string] : unknown;
}

ServiceInfo

The shape returned by the info operation and info command:

typescript
interface ServiceInfo
{
    id : string;
    serviceName : string;
    serviceGroup : string;
    version : string;
    strataVersion : string;
    environment : string;
    concurrency : number;
    outstanding : number;
    hostname : string;
    lastBusy : { time : Date, lag : number };
    contexts : Record<string, string[]>;
    backend : BackendInfo;
}