mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 01:19:38 +02:00
Use Duration for messaging runtime config
This commit is contained in:
parent
09d34fb4d4
commit
71edff47ed
5 changed files with 164 additions and 62 deletions
|
|
@ -1546,6 +1546,34 @@ Notes:
|
||||||
- `cd ts && bun run lint`
|
- `cd ts && bun run lint`
|
||||||
- `git diff --check`
|
- `git diff --check`
|
||||||
|
|
||||||
|
### 2026-06-02: Messaging Runtime Duration Config Slice
|
||||||
|
|
||||||
|
- Status: migrated and package-verified.
|
||||||
|
- Completed:
|
||||||
|
- `ts/packages/base/src/runtime/messaging-config.ts` now stores internal
|
||||||
|
runtime timing fields as `Duration.Duration` instead of number-shaped
|
||||||
|
millisecond fields.
|
||||||
|
- `loadMessagingRuntimeConfig()` reads `TG_*` timing env vars with
|
||||||
|
`Config.duration` while preserving legacy bare-number millisecond env
|
||||||
|
values through a `Config.number(...).map(Duration.millis)` fallback.
|
||||||
|
- `ts/packages/base/src/messaging/runtime.ts` now uses `Duration` values
|
||||||
|
directly for sleeps, retry schedules, and timeout options. It converts back
|
||||||
|
to milliseconds only at the broker `receive(timeoutMs)` boundary and for
|
||||||
|
existing timeout error payloads.
|
||||||
|
- Public compatibility options such as `receiveTimeoutMs`,
|
||||||
|
`rateLimitRetryMs`, `rateLimitTimeoutMs`, and request `timeoutMs` remain
|
||||||
|
numeric millisecond inputs.
|
||||||
|
- Tests now cover both legacy numeric env values and native Effect duration
|
||||||
|
strings.
|
||||||
|
- Verification:
|
||||||
|
- `cd ts && bun run check:tsgo`
|
||||||
|
- `cd ts/packages/base && bunx --bun vitest run src/__tests__/schema-effect.test.ts src/__tests__/messaging-runtime.test.ts src/__tests__/consumer.test.ts`
|
||||||
|
- `cd ts/packages/base && bun run build`
|
||||||
|
- `cd ts && bun run build`
|
||||||
|
- `cd ts && bun run test`
|
||||||
|
- `cd ts && bun run lint`
|
||||||
|
- `git diff --check`
|
||||||
|
|
||||||
## Subagent Findings To Preserve
|
## Subagent Findings To Preserve
|
||||||
|
|
||||||
- MCP/workbench:
|
- MCP/workbench:
|
||||||
|
|
@ -1658,10 +1686,10 @@ Notes:
|
||||||
gateway translation, and pure term helper switches. Future work should
|
gateway translation, and pure term helper switches. Future work should
|
||||||
only reopen this if client socket schema drift appears or a hidden
|
only reopen this if client socket schema drift appears or a hidden
|
||||||
consumer needs a different named-graph shape.
|
consumer needs a different named-graph shape.
|
||||||
- Messaging runtime `Config.duration` is the next strongest scratch target:
|
- Messaging runtime `Config.duration` cleanup is complete. Internal runtime
|
||||||
internal runtime config can use `Duration.Duration` while public
|
config uses `Duration.Duration`; public timeout compatibility inputs and
|
||||||
`timeoutMs` compatibility surfaces stay numeric.
|
broker receive/error payload boundaries remain numeric milliseconds.
|
||||||
- Qdrant graph/doc known-collection caches are a good small
|
- Qdrant graph/doc known-collection caches are the next good small
|
||||||
`MutableHashSet<string>` candidate; short-lived local traversal sets
|
`MutableHashSet<string>` candidate; short-lived local traversal sets
|
||||||
remain no-ops.
|
remain no-ops.
|
||||||
- FlowManager and sibling service `() => Effect.gen(...)` factories remain a
|
- FlowManager and sibling service `() => Effect.gen(...)` factories remain a
|
||||||
|
|
@ -1776,7 +1804,7 @@ Notes:
|
||||||
triples, compact graph strings, malformed known-tag payloads, and
|
triples, compact graph strings, malformed known-tag payloads, and
|
||||||
malformed client triple failures.
|
malformed client triple failures.
|
||||||
|
|
||||||
### P1: Messaging Runtime Duration Config Cleanup
|
### Complete: Messaging Runtime Duration Config Cleanup
|
||||||
|
|
||||||
- TrustGraph evidence:
|
- TrustGraph evidence:
|
||||||
- `ts/packages/base/src/runtime/messaging-config.ts`
|
- `ts/packages/base/src/runtime/messaging-config.ts`
|
||||||
|
|
@ -1794,8 +1822,9 @@ Notes:
|
||||||
processor, and client boundaries unless their public API is deliberately
|
processor, and client boundaries unless their public API is deliberately
|
||||||
changed.
|
changed.
|
||||||
- Tests:
|
- Tests:
|
||||||
- Extend base runtime config tests for env duration parsing and verify
|
- Base runtime config tests cover legacy millisecond env values and Effect
|
||||||
messaging retry/timeout behavior still uses the same effective durations.
|
duration string env values.
|
||||||
|
- Messaging runtime and consumer tests preserve retry and timeout behavior.
|
||||||
|
|
||||||
### P2: Qdrant Known-Collection MutableHashSet Cleanup
|
### P2: Qdrant Known-Collection MutableHashSet Cleanup
|
||||||
|
|
||||||
|
|
@ -1848,10 +1877,10 @@ Notes:
|
||||||
|
|
||||||
## Recommended PR Order
|
## Recommended PR Order
|
||||||
|
|
||||||
1. Messaging runtime `Config.duration` / `Duration` cleanup.
|
1. Qdrant known-collection `MutableHashSet` cleanup.
|
||||||
2. Qdrant known-collection `MutableHashSet` cleanup.
|
2. MCP protocol parity tests and legacy stdio flip/removal decision.
|
||||||
3. MCP protocol parity tests and legacy stdio flip/removal decision.
|
3. FlowManager/service `Effect.fn` normalization.
|
||||||
4. FlowManager/service `Effect.fn` normalization.
|
4. Flow/client RPC stream and remaining service operation `Match` follow-ups.
|
||||||
|
|
||||||
## No-Op Rules
|
## No-Op Rules
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ describe("Effect-native messaging runtime", () => {
|
||||||
PubSub.fromBackend(backend),
|
PubSub.fromBackend(backend),
|
||||||
{
|
{
|
||||||
...defaultMessagingRuntimeConfig,
|
...defaultMessagingRuntimeConfig,
|
||||||
consumerReceiveTimeoutMs: 1,
|
consumerReceiveTimeout: Duration.millis(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
requestTopic: "tg.test.request",
|
requestTopic: "tg.test.request",
|
||||||
|
|
@ -378,7 +378,7 @@ describe("Effect-native messaging runtime", () => {
|
||||||
PubSub.fromBackend(backend),
|
PubSub.fromBackend(backend),
|
||||||
{
|
{
|
||||||
...defaultMessagingRuntimeConfig,
|
...defaultMessagingRuntimeConfig,
|
||||||
consumerReceiveTimeoutMs: 1,
|
consumerReceiveTimeout: Duration.millis(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
requestTopic: "tg.test.request",
|
requestTopic: "tg.test.request",
|
||||||
|
|
@ -417,7 +417,7 @@ describe("Effect-native messaging runtime", () => {
|
||||||
PubSub.fromBackend(backend),
|
PubSub.fromBackend(backend),
|
||||||
{
|
{
|
||||||
...defaultMessagingRuntimeConfig,
|
...defaultMessagingRuntimeConfig,
|
||||||
consumerReceiveTimeoutMs: 1,
|
consumerReceiveTimeout: Duration.millis(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
requestTopic: "tg.test.request",
|
requestTopic: "tg.test.request",
|
||||||
|
|
@ -452,7 +452,7 @@ describe("Effect-native messaging runtime", () => {
|
||||||
PubSub.fromBackend(backend),
|
PubSub.fromBackend(backend),
|
||||||
{
|
{
|
||||||
...defaultMessagingRuntimeConfig,
|
...defaultMessagingRuntimeConfig,
|
||||||
consumerReceiveTimeoutMs: 1,
|
consumerReceiveTimeout: Duration.millis(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
requestTopic: "tg.test.request",
|
requestTopic: "tg.test.request",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, expect, it } from "@effect/vitest";
|
import { describe, expect, it } from "@effect/vitest";
|
||||||
import { ConfigProvider, Effect } from "effect";
|
import { ConfigProvider, Duration, Effect } from "effect";
|
||||||
import * as S from "effect/Schema";
|
import * as S from "effect/Schema";
|
||||||
import {
|
import {
|
||||||
ConfigRequest,
|
ConfigRequest,
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
Term,
|
Term,
|
||||||
TextCompletionRequest,
|
TextCompletionRequest,
|
||||||
Triple,
|
Triple,
|
||||||
|
loadMessagingRuntimeConfig,
|
||||||
loadProcessorRuntimeConfig,
|
loadProcessorRuntimeConfig,
|
||||||
} from "../index.js";
|
} from "../index.js";
|
||||||
|
|
||||||
|
|
@ -107,4 +108,56 @@ describe("Effect runtime config", () => {
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it.effect(
|
||||||
|
"loads messaging durations from legacy millisecond env values",
|
||||||
|
Effect.fnUntraced(function* () {
|
||||||
|
const provider = ConfigProvider.fromEnv({
|
||||||
|
env: {
|
||||||
|
TG_CONSUMER_RECEIVE_TIMEOUT_MS: "5",
|
||||||
|
TG_CONSUMER_ERROR_BACKOFF_MS: "10",
|
||||||
|
TG_RATE_LIMIT_RETRY_MS: "15",
|
||||||
|
TG_RATE_LIMIT_TIMEOUT_MS: "20",
|
||||||
|
TG_REQUEST_TIMEOUT_MS: "25",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = yield* Effect.provide(
|
||||||
|
loadMessagingRuntimeConfig(),
|
||||||
|
ConfigProvider.layer(provider),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(Duration.toMillis(config.consumerReceiveTimeout)).toBe(5);
|
||||||
|
expect(Duration.toMillis(config.consumerErrorBackoff)).toBe(10);
|
||||||
|
expect(Duration.toMillis(config.rateLimitRetry)).toBe(15);
|
||||||
|
expect(Duration.toMillis(config.rateLimitTimeout)).toBe(20);
|
||||||
|
expect(Duration.toMillis(config.requestTimeout)).toBe(25);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
it.effect(
|
||||||
|
"loads messaging durations from Effect duration env values",
|
||||||
|
Effect.fnUntraced(function* () {
|
||||||
|
const provider = ConfigProvider.fromEnv({
|
||||||
|
env: {
|
||||||
|
TG_CONSUMER_RECEIVE_TIMEOUT_MS: "2 seconds",
|
||||||
|
TG_CONSUMER_ERROR_BACKOFF_MS: "3 seconds",
|
||||||
|
TG_RATE_LIMIT_RETRY_MS: "4 seconds",
|
||||||
|
TG_RATE_LIMIT_TIMEOUT_MS: "5 seconds",
|
||||||
|
TG_REQUEST_TIMEOUT_MS: "6 seconds",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = yield* Effect.provide(
|
||||||
|
loadMessagingRuntimeConfig(),
|
||||||
|
ConfigProvider.layer(provider),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(Duration.toMillis(config.consumerReceiveTimeout)).toBe(2_000);
|
||||||
|
expect(Duration.toMillis(config.consumerErrorBackoff)).toBe(3_000);
|
||||||
|
expect(Duration.toMillis(config.rateLimitRetry)).toBe(4_000);
|
||||||
|
expect(Duration.toMillis(config.rateLimitTimeout)).toBe(5_000);
|
||||||
|
expect(Duration.toMillis(config.requestTimeout)).toBe(6_000);
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,12 @@ import {
|
||||||
|
|
||||||
const isTooManyRequestsError = S.is(TooManyRequestsError);
|
const isTooManyRequestsError = S.is(TooManyRequestsError);
|
||||||
|
|
||||||
|
const durationFromMsOption = (
|
||||||
|
value: number | undefined,
|
||||||
|
fallback: Duration.Duration,
|
||||||
|
): Duration.Duration =>
|
||||||
|
value === undefined ? fallback : Duration.millis(value);
|
||||||
|
|
||||||
export type EffectMessageHandler<T, E = never, R = never> = (
|
export type EffectMessageHandler<T, E = never, R = never> = (
|
||||||
message: T,
|
message: T,
|
||||||
properties: Record<string, string>,
|
properties: Record<string, string>,
|
||||||
|
|
@ -254,8 +260,10 @@ const handleMessageWithRetry = Effect.fn("handleMessageWithRetry")(function* <T,
|
||||||
message: Message<T>,
|
message: Message<T>,
|
||||||
config: MessagingRuntimeConfig,
|
config: MessagingRuntimeConfig,
|
||||||
) {
|
) {
|
||||||
const rateLimitRetryMs = options.rateLimitRetryMs ?? config.rateLimitRetryMs;
|
const rateLimitRetry = durationFromMsOption(options.rateLimitRetryMs, config.rateLimitRetry);
|
||||||
const rateLimitTimeoutMs = options.rateLimitTimeoutMs ?? config.rateLimitTimeoutMs;
|
const rateLimitTimeout = durationFromMsOption(options.rateLimitTimeoutMs, config.rateLimitTimeout);
|
||||||
|
const rateLimitRetryMs = Duration.toMillis(rateLimitRetry);
|
||||||
|
const rateLimitTimeoutMs = Duration.toMillis(rateLimitTimeout);
|
||||||
const runHandler = (): Effect.Effect<void, TooManyRequestsError | MessagingHandlerError, R> =>
|
const runHandler = (): Effect.Effect<void, TooManyRequestsError | MessagingHandlerError, R> =>
|
||||||
options.handler(message.value(), message.properties(), flow).pipe(
|
options.handler(message.value(), message.properties(), flow).pipe(
|
||||||
Effect.mapError((error): TooManyRequestsError | MessagingHandlerError =>
|
Effect.mapError((error): TooManyRequestsError | MessagingHandlerError =>
|
||||||
|
|
@ -276,11 +284,11 @@ const handleMessageWithRetry = Effect.fn("handleMessageWithRetry")(function* <T,
|
||||||
: Effect.void,
|
: Effect.void,
|
||||||
),
|
),
|
||||||
Effect.retry({
|
Effect.retry({
|
||||||
schedule: Schedule.spaced(Duration.millis(rateLimitRetryMs)),
|
schedule: Schedule.spaced(rateLimitRetry),
|
||||||
while: isTooManyRequestsError,
|
while: isTooManyRequestsError,
|
||||||
}),
|
}),
|
||||||
Effect.timeoutOrElse({
|
Effect.timeoutOrElse({
|
||||||
duration: Duration.millis(rateLimitTimeoutMs),
|
duration: rateLimitTimeout,
|
||||||
orElse: () => Effect.fail(messagingTimeoutError("rate-limit", rateLimitTimeoutMs)),
|
orElse: () => Effect.fail(messagingTimeoutError("rate-limit", rateLimitTimeoutMs)),
|
||||||
}),
|
}),
|
||||||
Effect.mapError((error) =>
|
Effect.mapError((error) =>
|
||||||
|
|
@ -325,14 +333,18 @@ const consumerLoop = <T, E, R>(
|
||||||
options: EffectConsumerOptions<T, E, R>,
|
options: EffectConsumerOptions<T, E, R>,
|
||||||
flow: FlowContext<R>,
|
flow: FlowContext<R>,
|
||||||
config: MessagingRuntimeConfig,
|
config: MessagingRuntimeConfig,
|
||||||
): Effect.Effect<void, never, R> =>
|
): Effect.Effect<void, never, R> => {
|
||||||
Effect.whileLoop({
|
const receiveTimeout = durationFromMsOption(options.receiveTimeoutMs, config.consumerReceiveTimeout);
|
||||||
|
const receiveTimeoutMs = Duration.toMillis(receiveTimeout);
|
||||||
|
const errorBackoff = durationFromMsOption(options.errorBackoffMs, config.consumerErrorBackoff);
|
||||||
|
|
||||||
|
return Effect.whileLoop({
|
||||||
while: () => true,
|
while: () => true,
|
||||||
body: () =>
|
body: () =>
|
||||||
receiveMessage(backend, options.topic, options.receiveTimeoutMs ?? config.consumerReceiveTimeoutMs).pipe(
|
receiveMessage(backend, options.topic, receiveTimeoutMs).pipe(
|
||||||
Effect.flatMap((message) =>
|
Effect.flatMap((message) =>
|
||||||
message === null
|
message === null
|
||||||
? Effect.sleep(Duration.millis(options.receiveTimeoutMs ?? config.consumerReceiveTimeoutMs))
|
? Effect.sleep(receiveTimeout)
|
||||||
: processConsumerMessage(backend, options, flow, message, config),
|
: processConsumerMessage(backend, options, flow, message, config),
|
||||||
),
|
),
|
||||||
Effect.catch((error) =>
|
Effect.catch((error) =>
|
||||||
|
|
@ -342,13 +354,14 @@ const consumerLoop = <T, E, R>(
|
||||||
subscription: options.subscription,
|
subscription: options.subscription,
|
||||||
}).pipe(
|
}).pipe(
|
||||||
Effect.flatMap(() =>
|
Effect.flatMap(() =>
|
||||||
Effect.sleep(Duration.millis(options.errorBackoffMs ?? config.consumerErrorBackoffMs)),
|
Effect.sleep(errorBackoff),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
step: () => undefined,
|
step: () => undefined,
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const makeEffectConsumerFromPubSub = Effect.fn("makeEffectConsumerFromPubSub")(function* <T, E, R>(
|
export const makeEffectConsumerFromPubSub = Effect.fn("makeEffectConsumerFromPubSub")(function* <T, E, R>(
|
||||||
pubsub: PubSubService,
|
pubsub: PubSubService,
|
||||||
|
|
@ -364,15 +377,10 @@ export const makeEffectConsumerFromPubSub = Effect.fn("makeEffectConsumerFromPub
|
||||||
};
|
};
|
||||||
const concurrency = Math.max(1, options.concurrency ?? 1);
|
const concurrency = Math.max(1, options.concurrency ?? 1);
|
||||||
const workerIndexes = Array.from({ length: concurrency }, (_value, index) => index);
|
const workerIndexes = Array.from({ length: concurrency }, (_value, index) => index);
|
||||||
const workerConfig = {
|
|
||||||
...config,
|
|
||||||
rateLimitRetryMs: options.rateLimitRetryMs ?? config.rateLimitRetryMs,
|
|
||||||
rateLimitTimeoutMs: options.rateLimitTimeoutMs ?? config.rateLimitTimeoutMs,
|
|
||||||
};
|
|
||||||
const workers = yield* Effect.forEach(workerIndexes, () =>
|
const workers = yield* Effect.forEach(workerIndexes, () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const backend = yield* pubsub.createConsumer<T>(createOptions);
|
const backend = yield* pubsub.createConsumer<T>(createOptions);
|
||||||
const fiber = yield* consumerLoop(backend, options, flow, workerConfig).pipe(Effect.forkScoped);
|
const fiber = yield* consumerLoop(backend, options, flow, config).pipe(Effect.forkScoped);
|
||||||
return { backend, fiber };
|
return { backend, fiber };
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -417,10 +425,10 @@ const dispatchResponseLoop = <T>(
|
||||||
Effect.whileLoop({
|
Effect.whileLoop({
|
||||||
while: () => true,
|
while: () => true,
|
||||||
body: () =>
|
body: () =>
|
||||||
receiveMessage(backend, responseTopic, config.consumerReceiveTimeoutMs).pipe(
|
receiveMessage(backend, responseTopic, Duration.toMillis(config.consumerReceiveTimeout)).pipe(
|
||||||
Effect.flatMap((message) => {
|
Effect.flatMap((message) => {
|
||||||
if (message === null) {
|
if (message === null) {
|
||||||
return Effect.sleep(Duration.millis(config.consumerReceiveTimeoutMs));
|
return Effect.sleep(config.consumerReceiveTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = message.properties().id;
|
const id = message.properties().id;
|
||||||
|
|
@ -438,7 +446,7 @@ const dispatchResponseLoop = <T>(
|
||||||
Effect.logError("[RequestResponse] Response dispatch failed", {
|
Effect.logError("[RequestResponse] Response dispatch failed", {
|
||||||
error: error.message,
|
error: error.message,
|
||||||
topic: responseTopic,
|
topic: responseTopic,
|
||||||
}).pipe(Effect.flatMap(() => Effect.sleep(Duration.millis(config.consumerErrorBackoffMs)))),
|
}).pipe(Effect.flatMap(() => Effect.sleep(config.consumerErrorBackoff))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
step: () => undefined,
|
step: () => undefined,
|
||||||
|
|
@ -532,7 +540,8 @@ export const makeEffectRequestResponseFromPubSub = Effect.fn("makeEffectRequestR
|
||||||
requestOptions?: EffectRequestOptions<TRes, E, R>,
|
requestOptions?: EffectRequestOptions<TRes, E, R>,
|
||||||
) => {
|
) => {
|
||||||
const id = randomUUID();
|
const id = randomUUID();
|
||||||
const timeoutMs = requestOptions?.timeoutMs ?? config.requestTimeoutMs;
|
const timeout = durationFromMsOption(requestOptions?.timeoutMs, config.requestTimeout);
|
||||||
|
const timeoutMs = Duration.toMillis(timeout);
|
||||||
|
|
||||||
return Effect.scoped(
|
return Effect.scoped(
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|
@ -540,7 +549,7 @@ export const makeEffectRequestResponseFromPubSub = Effect.fn("makeEffectRequestR
|
||||||
yield* producer.send(id, request);
|
yield* producer.send(id, request);
|
||||||
const result = yield* waitForResponse(subscription, id, requestOptions).pipe(
|
const result = yield* waitForResponse(subscription, id, requestOptions).pipe(
|
||||||
Effect.raceFirst(Deferred.await(stoppedSignal)),
|
Effect.raceFirst(Deferred.await(stoppedSignal)),
|
||||||
Effect.timeoutOption(Duration.millis(timeoutMs)),
|
Effect.timeoutOption(timeout),
|
||||||
);
|
);
|
||||||
return yield* O.match(result, {
|
return yield* O.match(result, {
|
||||||
onNone: () => Effect.fail(messagingTimeoutError("request-response", timeoutMs)),
|
onNone: () => Effect.fail(messagingTimeoutError("request-response", timeoutMs)),
|
||||||
|
|
|
||||||
|
|
@ -2,46 +2,57 @@
|
||||||
* Effect Config contracts for messaging runtime behavior.
|
* Effect Config contracts for messaging runtime behavior.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Config, Effect } from "effect";
|
import { Config, Duration, Effect } from "effect";
|
||||||
|
|
||||||
export interface MessagingRuntimeConfig {
|
export interface MessagingRuntimeConfig {
|
||||||
readonly consumerReceiveTimeoutMs: number;
|
readonly consumerReceiveTimeout: Duration.Duration;
|
||||||
readonly consumerErrorBackoffMs: number;
|
readonly consumerErrorBackoff: Duration.Duration;
|
||||||
readonly rateLimitRetryMs: number;
|
readonly rateLimitRetry: Duration.Duration;
|
||||||
readonly rateLimitTimeoutMs: number;
|
readonly rateLimitTimeout: Duration.Duration;
|
||||||
readonly requestTimeoutMs: number;
|
readonly requestTimeout: Duration.Duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultMessagingRuntimeConfig: MessagingRuntimeConfig = {
|
export const defaultMessagingRuntimeConfig: MessagingRuntimeConfig = {
|
||||||
consumerReceiveTimeoutMs: 2_000,
|
consumerReceiveTimeout: Duration.millis(2_000),
|
||||||
consumerErrorBackoffMs: 1_000,
|
consumerErrorBackoff: Duration.millis(1_000),
|
||||||
rateLimitRetryMs: 10_000,
|
rateLimitRetry: Duration.millis(10_000),
|
||||||
rateLimitTimeoutMs: 7_200_000,
|
rateLimitTimeout: Duration.millis(7_200_000),
|
||||||
requestTimeoutMs: 300_000,
|
requestTimeout: Duration.millis(300_000),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const durationConfig = (name: string, defaultValue: Duration.Duration) =>
|
||||||
|
Config.duration(name).pipe(
|
||||||
|
Config.orElse(() => Config.number(name).pipe(Config.map(Duration.millis))),
|
||||||
|
Config.withDefault(defaultValue),
|
||||||
|
);
|
||||||
|
|
||||||
export const loadMessagingRuntimeConfig = Effect.fn("loadMessagingRuntimeConfig")(function* () {
|
export const loadMessagingRuntimeConfig = Effect.fn("loadMessagingRuntimeConfig")(function* () {
|
||||||
const consumerReceiveTimeoutMs = yield* Config.number("TG_CONSUMER_RECEIVE_TIMEOUT_MS").pipe(
|
const consumerReceiveTimeout = yield* durationConfig(
|
||||||
Config.withDefault(defaultMessagingRuntimeConfig.consumerReceiveTimeoutMs),
|
"TG_CONSUMER_RECEIVE_TIMEOUT_MS",
|
||||||
|
defaultMessagingRuntimeConfig.consumerReceiveTimeout,
|
||||||
);
|
);
|
||||||
const consumerErrorBackoffMs = yield* Config.number("TG_CONSUMER_ERROR_BACKOFF_MS").pipe(
|
const consumerErrorBackoff = yield* durationConfig(
|
||||||
Config.withDefault(defaultMessagingRuntimeConfig.consumerErrorBackoffMs),
|
"TG_CONSUMER_ERROR_BACKOFF_MS",
|
||||||
|
defaultMessagingRuntimeConfig.consumerErrorBackoff,
|
||||||
);
|
);
|
||||||
const rateLimitRetryMs = yield* Config.number("TG_RATE_LIMIT_RETRY_MS").pipe(
|
const rateLimitRetry = yield* durationConfig(
|
||||||
Config.withDefault(defaultMessagingRuntimeConfig.rateLimitRetryMs),
|
"TG_RATE_LIMIT_RETRY_MS",
|
||||||
|
defaultMessagingRuntimeConfig.rateLimitRetry,
|
||||||
);
|
);
|
||||||
const rateLimitTimeoutMs = yield* Config.number("TG_RATE_LIMIT_TIMEOUT_MS").pipe(
|
const rateLimitTimeout = yield* durationConfig(
|
||||||
Config.withDefault(defaultMessagingRuntimeConfig.rateLimitTimeoutMs),
|
"TG_RATE_LIMIT_TIMEOUT_MS",
|
||||||
|
defaultMessagingRuntimeConfig.rateLimitTimeout,
|
||||||
);
|
);
|
||||||
const requestTimeoutMs = yield* Config.number("TG_REQUEST_TIMEOUT_MS").pipe(
|
const requestTimeout = yield* durationConfig(
|
||||||
Config.withDefault(defaultMessagingRuntimeConfig.requestTimeoutMs),
|
"TG_REQUEST_TIMEOUT_MS",
|
||||||
|
defaultMessagingRuntimeConfig.requestTimeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
consumerReceiveTimeoutMs,
|
consumerReceiveTimeout,
|
||||||
consumerErrorBackoffMs,
|
consumerErrorBackoff,
|
||||||
rateLimitRetryMs,
|
rateLimitRetry,
|
||||||
rateLimitTimeoutMs,
|
rateLimitTimeout,
|
||||||
requestTimeoutMs,
|
requestTimeout,
|
||||||
} satisfies MessagingRuntimeConfig;
|
} satisfies MessagingRuntimeConfig;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue