Loading .vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ "cfworker", "codegen", "cryptosuite", "decorrelated", "deflist", "Deno", "denokv", Loading CHANGES.md +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,16 @@ To be released. - The type of `InboxErrorHandler` callback type's first parameter became `Context` (was `RequestContext`). - Implemented fully customizable retry policy for failed tasks in the task queue. By default, the task queue retries the failed tasks with an exponential backoff policy with decorrelated jitter. - Added `outboxRetryPolicy` option to `CreateFederationOptions` interface. - Added `RetryPolicy` callback type. - Added `RetryContext` interface. - Added `createExponentialBackoffPolicy()` function. - Added `CreateExponentialBackoffPolicyOptions` interface. - Added `ChatMessage` class to Activity Vocabulary API. [[#85]] - Improved multitenancy (virtual hosting) support. [[#66]] Loading docs/manual/federation.md +17 −3 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ properties. Some of them are required: ### `kv` *Required.* The `~FederationOptions.kv` property is a `KvStore` instance *Required.* The `~CreateFederationOptions.kv` property is a `KvStore` instance that the `Federation` object uses to store several kinds of cache data and to maintain the queue of outgoing activities. Loading @@ -68,7 +68,7 @@ key-value store.[^1] ### `kvPrefixes` The `~FederationOptions.kvPrefixes` property is an object that contains The `~CreateFederationOptions.kvPrefixes` property is an object that contains the key prefixes for the cache data. The following are the key prefixes that the `Federation` object uses: Loading @@ -84,7 +84,7 @@ that the `Federation` object uses: *This API is available since Fedify 0.5.0.* The `~FederationOptions.queue` property is a `MessageQueue` instance that The `~CreateFederationOptions.queue` property is a `MessageQueue` instance that the `Federation` object uses to maintain the queue of incoming and outgoing activities. If you don't provide this option, activities will not be queued and will be processed immediately. Loading Loading @@ -152,6 +152,20 @@ load remote JSON-LD contexts. The type of the function is the same as the [*Document loader vs. context loader* section](./context.md#document-loader-vs-context-loader)). ### `outboxRetryPolicy` *This API is available since Fedify 0.12.0.* The retry policy for sending activities to recipients' inboxes. By default, this uses an exponential backoff strategy with a maximum of 10 attempts and a maximum delay of 12 hours. You can fully customize the retry policy by providing a custom function that satisfies the `RetryPolicy` type. Or you can adjust the parameters of the `createExponentialBackoffRetryPolicy()` function, which is a default implementation of the retry policy. How the `Federation` object recognizes the domain name ------------------------------------------------------ Loading federation/middleware.ts +37 −21 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import type { OutboxMessage, SenderKeyJwkPair, } from "./queue.ts"; import { createExponentialBackoffPolicy, type RetryPolicy } from "./retry.ts"; import { Router, RouterError } from "./router.ts"; import { extractInboxes, sendActivity, type SenderKeyPair } from "./send.ts"; Loading Loading @@ -120,13 +121,22 @@ export interface CreateFederationOptions { * the window is a minute. */ signatureTimeWindow?: Temporal.DurationLike; /** * The retry policy for sending activities to recipients' inboxes. * By default, this uses an exponential backoff strategy with a maximum of * 10 attempts and a maximum delay of 12 hours. * @since 0.12.0 */ outboxRetryPolicy?: RetryPolicy; } /** * Parameters for initializing a {@link Federation} instance. * @deprecated */ export interface FederationParameters extends CreateFederationOptions { export interface FederationParameters extends Omit<CreateFederationOptions, "outboxRetryPolicy"> { /** * The message queue for sending activities to recipients' inboxes. * If not provided, activities will not be queued and will be sent Loading Loading @@ -184,10 +194,6 @@ export interface FederationParameters extends CreateFederationOptions { * @deprecated */ treatHttps?: boolean; // TODO: The following option should be removed, and exponential backoff // should be used instead: backoffSchedule?: Temporal.Duration[]; } /** Loading Loading @@ -268,14 +274,15 @@ export class Federation<TContextData> { #treatHttps: boolean; #onOutboxError?: OutboxErrorHandler; #signatureTimeWindow: Temporal.DurationLike; #backoffSchedule: Temporal.Duration[]; #outboxRetryPolicy: RetryPolicy; /** * Create a new {@link Federation} instance. * @param parameters Parameters for initializing the instance. * @deprecated Use {@link createFederation} method instead. */ constructor(options: FederationParameters) { constructor(parameters: FederationParameters) { const options = parameters as CreateFederationOptions; const logger = getLogger(["fedify", "federation"]); // @ts-ignore: This is a private symbol. if (!options[invokedByCreateFederation]) { Loading Loading @@ -309,8 +316,8 @@ export class Federation<TContextData> { options.authenticatedDocumentLoaderFactory ?? getAuthenticatedDocumentLoader; this.#onOutboxError = options.onOutboxError; this.#treatHttps = options.treatHttps ?? false; if (options.treatHttps) { this.#treatHttps = parameters.treatHttps ?? false; if (parameters.treatHttps) { logger.warn( "The treatHttps option is deprecated and will be removed in " + "a future release. Instead, use the x-forwarded-fetch library" + Loading @@ -319,13 +326,8 @@ export class Federation<TContextData> { ); } this.#signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 }; this.#backoffSchedule = options.backoffSchedule ?? [ 3_000, 15_000, 60_000, 15 * 60_000, 60 * 60_000, ].map((ms) => Temporal.Duration.from({ milliseconds: ms })); this.#outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy(); } #startQueue(ctxData: TContextData) { Loading Loading @@ -397,16 +399,29 @@ export class Federation<TContextData> { { ...logData, error, activityId: activity?.id?.href }, ); } if (message.trial < this.#backoffSchedule.length) { const delay = this.#outboxRetryPolicy({ elapsedTime: Temporal.Instant.from(message.started).until( Temporal.Now.instant(), ), attempts: message.trial, }); if (delay != null) { logger.error( "Failed to send activity {activityId} to {inbox} (trial #{trial})" + "; retry...:\n{error}", { ...logData, error, activityId: activity?.id?.href }, ); this.#queue?.enqueue({ this.#queue?.enqueue( { ...message, trial: message.trial + 1, }, { delay: this.#backoffSchedule[message.trial] }); } satisfies OutboxMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay, }, ); } else { logger.error( "Failed to send activity {activityId} to {inbox} after {trial} " + Loading Loading @@ -1576,6 +1591,7 @@ export class Federation<TContextData> { keys: keyJwkPairs, activity: activityJson, inbox, started: new Date().toISOString(), trial: 0, headers: collectionSync == null ? {} : { "Collection-Synchronization": Loading federation/mod.ts +1 −0 Original line number Diff line number Diff line Loading @@ -14,5 +14,6 @@ export { export * from "./kv.ts"; export * from "./middleware.ts"; export * from "./mq.ts"; export * from "./retry.ts"; export * from "./router.ts"; export { type SenderKeyPair } from "./send.ts"; Loading
.vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ "cfworker", "codegen", "cryptosuite", "decorrelated", "deflist", "Deno", "denokv", Loading
CHANGES.md +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,16 @@ To be released. - The type of `InboxErrorHandler` callback type's first parameter became `Context` (was `RequestContext`). - Implemented fully customizable retry policy for failed tasks in the task queue. By default, the task queue retries the failed tasks with an exponential backoff policy with decorrelated jitter. - Added `outboxRetryPolicy` option to `CreateFederationOptions` interface. - Added `RetryPolicy` callback type. - Added `RetryContext` interface. - Added `createExponentialBackoffPolicy()` function. - Added `CreateExponentialBackoffPolicyOptions` interface. - Added `ChatMessage` class to Activity Vocabulary API. [[#85]] - Improved multitenancy (virtual hosting) support. [[#66]] Loading
docs/manual/federation.md +17 −3 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ properties. Some of them are required: ### `kv` *Required.* The `~FederationOptions.kv` property is a `KvStore` instance *Required.* The `~CreateFederationOptions.kv` property is a `KvStore` instance that the `Federation` object uses to store several kinds of cache data and to maintain the queue of outgoing activities. Loading @@ -68,7 +68,7 @@ key-value store.[^1] ### `kvPrefixes` The `~FederationOptions.kvPrefixes` property is an object that contains The `~CreateFederationOptions.kvPrefixes` property is an object that contains the key prefixes for the cache data. The following are the key prefixes that the `Federation` object uses: Loading @@ -84,7 +84,7 @@ that the `Federation` object uses: *This API is available since Fedify 0.5.0.* The `~FederationOptions.queue` property is a `MessageQueue` instance that The `~CreateFederationOptions.queue` property is a `MessageQueue` instance that the `Federation` object uses to maintain the queue of incoming and outgoing activities. If you don't provide this option, activities will not be queued and will be processed immediately. Loading Loading @@ -152,6 +152,20 @@ load remote JSON-LD contexts. The type of the function is the same as the [*Document loader vs. context loader* section](./context.md#document-loader-vs-context-loader)). ### `outboxRetryPolicy` *This API is available since Fedify 0.12.0.* The retry policy for sending activities to recipients' inboxes. By default, this uses an exponential backoff strategy with a maximum of 10 attempts and a maximum delay of 12 hours. You can fully customize the retry policy by providing a custom function that satisfies the `RetryPolicy` type. Or you can adjust the parameters of the `createExponentialBackoffRetryPolicy()` function, which is a default implementation of the retry policy. How the `Federation` object recognizes the domain name ------------------------------------------------------ Loading
federation/middleware.ts +37 −21 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import type { OutboxMessage, SenderKeyJwkPair, } from "./queue.ts"; import { createExponentialBackoffPolicy, type RetryPolicy } from "./retry.ts"; import { Router, RouterError } from "./router.ts"; import { extractInboxes, sendActivity, type SenderKeyPair } from "./send.ts"; Loading Loading @@ -120,13 +121,22 @@ export interface CreateFederationOptions { * the window is a minute. */ signatureTimeWindow?: Temporal.DurationLike; /** * The retry policy for sending activities to recipients' inboxes. * By default, this uses an exponential backoff strategy with a maximum of * 10 attempts and a maximum delay of 12 hours. * @since 0.12.0 */ outboxRetryPolicy?: RetryPolicy; } /** * Parameters for initializing a {@link Federation} instance. * @deprecated */ export interface FederationParameters extends CreateFederationOptions { export interface FederationParameters extends Omit<CreateFederationOptions, "outboxRetryPolicy"> { /** * The message queue for sending activities to recipients' inboxes. * If not provided, activities will not be queued and will be sent Loading Loading @@ -184,10 +194,6 @@ export interface FederationParameters extends CreateFederationOptions { * @deprecated */ treatHttps?: boolean; // TODO: The following option should be removed, and exponential backoff // should be used instead: backoffSchedule?: Temporal.Duration[]; } /** Loading Loading @@ -268,14 +274,15 @@ export class Federation<TContextData> { #treatHttps: boolean; #onOutboxError?: OutboxErrorHandler; #signatureTimeWindow: Temporal.DurationLike; #backoffSchedule: Temporal.Duration[]; #outboxRetryPolicy: RetryPolicy; /** * Create a new {@link Federation} instance. * @param parameters Parameters for initializing the instance. * @deprecated Use {@link createFederation} method instead. */ constructor(options: FederationParameters) { constructor(parameters: FederationParameters) { const options = parameters as CreateFederationOptions; const logger = getLogger(["fedify", "federation"]); // @ts-ignore: This is a private symbol. if (!options[invokedByCreateFederation]) { Loading Loading @@ -309,8 +316,8 @@ export class Federation<TContextData> { options.authenticatedDocumentLoaderFactory ?? getAuthenticatedDocumentLoader; this.#onOutboxError = options.onOutboxError; this.#treatHttps = options.treatHttps ?? false; if (options.treatHttps) { this.#treatHttps = parameters.treatHttps ?? false; if (parameters.treatHttps) { logger.warn( "The treatHttps option is deprecated and will be removed in " + "a future release. Instead, use the x-forwarded-fetch library" + Loading @@ -319,13 +326,8 @@ export class Federation<TContextData> { ); } this.#signatureTimeWindow = options.signatureTimeWindow ?? { minutes: 1 }; this.#backoffSchedule = options.backoffSchedule ?? [ 3_000, 15_000, 60_000, 15 * 60_000, 60 * 60_000, ].map((ms) => Temporal.Duration.from({ milliseconds: ms })); this.#outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy(); } #startQueue(ctxData: TContextData) { Loading Loading @@ -397,16 +399,29 @@ export class Federation<TContextData> { { ...logData, error, activityId: activity?.id?.href }, ); } if (message.trial < this.#backoffSchedule.length) { const delay = this.#outboxRetryPolicy({ elapsedTime: Temporal.Instant.from(message.started).until( Temporal.Now.instant(), ), attempts: message.trial, }); if (delay != null) { logger.error( "Failed to send activity {activityId} to {inbox} (trial #{trial})" + "; retry...:\n{error}", { ...logData, error, activityId: activity?.id?.href }, ); this.#queue?.enqueue({ this.#queue?.enqueue( { ...message, trial: message.trial + 1, }, { delay: this.#backoffSchedule[message.trial] }); } satisfies OutboxMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay, }, ); } else { logger.error( "Failed to send activity {activityId} to {inbox} after {trial} " + Loading Loading @@ -1576,6 +1591,7 @@ export class Federation<TContextData> { keys: keyJwkPairs, activity: activityJson, inbox, started: new Date().toISOString(), trial: 0, headers: collectionSync == null ? {} : { "Collection-Synchronization": Loading
federation/mod.ts +1 −0 Original line number Diff line number Diff line Loading @@ -14,5 +14,6 @@ export { export * from "./kv.ts"; export * from "./middleware.ts"; export * from "./mq.ts"; export * from "./retry.ts"; export * from "./router.ts"; export { type SenderKeyPair } from "./send.ts";