Client (StrataClient)
The StrataClient class sends requests to services and receives responses. It also supports fire-and-forget posts, service commands, and service discovery.
For conceptual background, see Architecture.
import { StrataClient } from '@strata-js/strata';Constructor
new StrataClient(config : StrataClientConfig)Creates a new client instance.
const client = new StrataClient({
client: { name: 'MyApp' },
backend: {
type: 'redis-streams',
redis: { host: 'localhost', port: 6379 },
},
});The client name defaults to Client:<serviceGroup> if service.serviceGroup is set in config, or StrataClient.<hostname> otherwise.
Properties
| Property | Type | Description |
|---|---|---|
id | string | Auto-generated unique ID (or override via config.client.id). |
name | string | Client name for identification on the wire. |
version | string | Application version (from package.json or APP_VERSION). |
config | StrataClientConfig | The config object passed to the constructor. |
initialized | boolean | true after start() has been called. |
outstandingRequests | Map<string, StrataRequest> | Currently in-flight requests waiting for responses. |
Methods
start()
client.start() : Promise<void>Initializes the backend and starts listening for responses. You must call this before making any requests or sending commands.
Throws AlreadyInitializedError if called more than once.
const client = new StrataClient(config);
await client.start();request()
client.request<ReturnPayloadType, MetadataType>(
queueOrService : string,
context : string,
operation : string,
payload : Record<string, unknown>,
metadata ?: MetadataType,
auth ?: string,
timeout ?: number
) : Promise<ResponseEnvelope<ReturnPayloadType>>Sends a request and waits for a response. This is the primary way to call operations on a service.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
queueOrService | string | yes | Service group name or queue name. The Requests: prefix is added automatically if missing. |
context | string | yes | Target context name. |
operation | string | yes | Target operation name. |
payload | Record<string, unknown> | yes | Request payload. |
metadata | Record<string, unknown> | no | Request metadata (tracking, stats, etc.). |
auth | string | no | Authentication token (typically a JWT). |
timeout | number | no | Request timeout in milliseconds. 0 or omitted uses the service default. |
Returns: Promise<ResponseEnvelope<ReturnPayloadType>> -- the full response envelope.
const response = await client.request('UserService', 'users', 'get', {
userId: '12345',
});
console.log(response.status); // 'succeeded'
console.log(response.payload); // { user: { ... } }Throws UninitializedError if the client hasn't been started.
post()
client.post<MetadataType>(
queueOrService : string,
context : string,
operation : string,
payload : Record<string, unknown>,
metadata ?: MetadataType,
auth ?: string
) : Promise<void>Sends a fire-and-forget message. The service processes it but sends no response. Useful for events, notifications, or any case where the sender doesn't need confirmation.
await client.post('NotificationService', 'email', 'send', {
to: 'user@example.com',
subject: 'Welcome!',
body: 'Thanks for signing up.',
});Throws UninitializedError if the client hasn't been started.
command()
client.command(
command : ValidCommandName,
target ?: string,
payload ?: Record<string, unknown>
) : Promise<ServiceCommandResponse | undefined>Sends a command to one or more running services. Commands control service behavior at runtime (shutdown, concurrency changes, etc.).
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
command | ValidCommandName | -- | One of 'info', 'concurrency', 'shutdown', 'toobusy'. |
target | string | 'Services' | Target scope for the command. |
payload | object | -- | Command-specific payload. |
Target format:
| Target | Scope |
|---|---|
'Services' | All running services (all groups). |
'Services:<serviceGroup>' | All instances in a specific service group. |
'Services:<serviceGroup>:<id>' | A specific service instance by ID. |
Returns: A ServiceCommandResponse for commands that have replies (currently only info), or undefined.
// Get info from all services
const info = await client.command('info');
// Shut down a specific service group
await client.command('shutdown', 'Services:UserService', {
graceful: true,
});
// Update concurrency for all services
await client.command('concurrency', 'Services', {
concurrency: 64,
});Built-in Commands
| Command | Payload | Has Response | Description |
|---|---|---|---|
info | -- | yes | Returns ServiceInfo for each instance. |
shutdown | { graceful?, exitCode? } | no | Initiates service shutdown. |
concurrency | { concurrency } | no | Updates max concurrent requests. |
toobusy | TooBusyConfig | no | Updates node-toobusy options. |
discoverServices()
client.discoverServices() : Promise<DiscoveredServices>Returns all discovered service groups, their instances, and what contexts/operations each supports. The return type is a nested record: service group name -> service instance ID -> DiscoveredService.
const services = await client.discoverServices();
for(const [ group, instances ] of Object.entries(services))
{
console.log(`Service group: ${ group }`);
for(const [ id, info ] of Object.entries(instances))
{
console.log(` Instance ${ id }: v${ info.version }, ${ info.outstanding } outstanding`);
console.log(` Contexts:`, Object.keys(info.contexts));
}
}INFO
Service discovery requires the backend to support it and discovery to be enabled in the service config (enabled by default).
registerBackend()
client.registerBackend(name : string, backendClass : BackendConstructor) : voidRegisters a custom backend constructor, just like service.registerBackend(). Use this when the client needs a backend that isn't built in.
getBackend()
client.getBackend<T extends BaseStrataBackend>(name : string) : TReturns the backend instance registered under the given name.
Configuration Reference
StrataClientConfig
type StrataClientConfig = Omit<StrataConfig, 'service'> & {
service ?: Partial<ServiceConfig>;
};In practice, a client config looks like:
{
client: {
name: 'MyApp', // Optional. Defaults based on serviceGroup or hostname.
id: 'custom-id', // Optional. Auto-generated if omitted.
},
backend: {
type: 'redis-streams',
redis: { host: 'localhost', port: 6379 },
},
aliases: { // Optional. Map friendly names to queue names.
'users': 'UserService',
},
}ClientConfig
interface ClientConfig
{
name ?: string;
id ?: string;
}