@fedify/fedify 2.3.0-dev.1079 → 2.3.0-dev.1110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{builder-DqT-OPZ8.mjs → builder-B-Y6fwSu.mjs} +2 -2
- package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
- package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
- package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
- package/dist/compat/mod.d.cts +2 -1
- package/dist/compat/mod.d.ts +2 -3
- package/dist/compat/mod.js +3 -3
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{context-DrNqYkPw.d.ts → context-C0C_sRha.d.cts} +6 -7
- package/dist/{context-BKLGj9QO.d.cts → context-Dqgt8saU.d.ts} +6 -5
- package/dist/{deno-BxqkYxIf.mjs → deno-hqC7tKJn.mjs} +1 -1
- package/dist/{docloader-vsZP01ww.mjs → docloader-BOEuuXkX.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +84 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/middleware.test.mjs +383 -16
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +4 -3
- package/dist/federation/mod.d.ts +4 -5
- package/dist/federation/mod.js +2 -2
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{http-CrGuipxe.d.cts → http-BDZeS5om.d.ts} +2 -1
- package/dist/{http-DM4ZAFCe.mjs → http-BLopFpvC.mjs} +58 -10
- package/dist/{http-aQzN9Ayi.d.ts → http-C87EWkO0.d.cts} +2 -3
- package/dist/{http-DQ25_ruv.cjs → http-DV0il3vk.cjs} +57 -9
- package/dist/{http-b__OS_rJ.js → http-O8MYWwk8.js} +58 -10
- package/dist/{key-BNp_b9oE.mjs → key-DW1EVmtP.mjs} +1 -1
- package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
- package/dist/{kv-cache-D5vjOi5y.js → kv-cache-C3NWWiTg.js} +2 -2
- package/dist/{kv-cache-EaVpV2xQ.mjs → kv-cache-CiiNwT6W.mjs} +1 -1
- package/dist/{kv-cache-DzctboPD.cjs → kv-cache-Dya-TWMe.cjs} +2 -2
- package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
- package/dist/{ld-L9w529xq.mjs → ld-BNkk2Yal.mjs} +2 -2
- package/dist/{middleware-DZNHpEbh.js → middleware-CjzI3aYo.js} +309 -111
- package/dist/{middleware-CpCSD43m.mjs → middleware-D6FbOjuK.mjs} +1 -1
- package/dist/{middleware-CTdNwf_s.mjs → middleware-DA2WTBr4.mjs} +188 -114
- package/dist/{middleware-CMF242Rg.cjs → middleware-DUWeXjZR.cjs} +305 -107
- package/dist/{mod-CLgIXe9w.d.ts → mod-B0rWmfW5.d.cts} +4 -5
- package/dist/{mod-CMEbIaNh.d.cts → mod-BhU_H1I_.d.ts} +4 -3
- package/dist/{mod-B8Z8mBLk.d.ts → mod-CLPnQPsv.d.cts} +2 -3
- package/dist/{mod-Cr3f-ACa.d.cts → mod-DHO9lk3D.d.ts} +3 -2
- package/dist/{mod-CR8soWa9.d.ts → mod-DXY9JF28.d.cts} +3 -4
- package/dist/{mod-DClCOv0M.d.cts → mod-Dx3-hqyo.d.ts} +2 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +9 -8
- package/dist/mod.d.ts +9 -10
- package/dist/mod.js +9 -9
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/nodeinfo/mod.d.cts +2 -1
- package/dist/nodeinfo/mod.d.ts +2 -3
- package/dist/nodeinfo/mod.js +3 -3
- package/dist/otel/mod.d.cts +2 -1
- package/dist/otel/mod.d.ts +2 -3
- package/dist/otel/mod.js +2 -2
- package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
- package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
- package/dist/{owner-C30LGgMz.mjs → owner-jvJAtR5O.mjs} +2 -2
- package/dist/{proof-CO1qAbN8.js → proof-5kT7OUPV.js} +2 -2
- package/dist/{proof-zrLeLWgt.cjs → proof-BD92WeqV.cjs} +1 -1
- package/dist/{proof-BjToRsXF.mjs → proof-mfmHH9j0.mjs} +2 -2
- package/dist/runtime/mod.d.cts +1 -0
- package/dist/runtime/mod.d.ts +1 -2
- package/dist/runtime/mod.js +3 -3
- package/dist/{send-DzbMznU6.mjs → send-hokVCPu6.mjs} +127 -3
- package/dist/sig/http.test.mjs +120 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +4 -3
- package/dist/sig/mod.d.ts +4 -5
- package/dist/sig/mod.js +4 -4
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
- package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +2 -1
- package/dist/utils/mod.d.ts +2 -3
- package/dist/utils/mod.js +3 -3
- package/dist/vocab/mod.d.cts +1 -0
- package/dist/vocab/mod.d.ts +1 -2
- package/dist/vocab/mod.js +2 -2
- package/package.json +7 -7
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
import { t as __exportAll } from "./chunk-
|
|
4
|
-
import { r as getDefaultActivityTransformers } from "./transformers-
|
|
5
|
-
import { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-
|
|
6
|
-
import { c as getKeyOwner, d as detachSignature, f as hasSignatureLike, i as verifyObject, m as verifyJsonLd, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, p as signJsonLd, r as signObject, s as doesActorOwnKey } from "./proof-
|
|
7
|
-
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-
|
|
8
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-
|
|
2
|
+
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
+
import { t as __exportAll } from "./chunk-CRNNMoPX.js";
|
|
4
|
+
import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
|
|
5
|
+
import { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-O8MYWwk8.js";
|
|
6
|
+
import { c as getKeyOwner, d as detachSignature, f as hasSignatureLike, i as verifyObject, m as verifyJsonLd, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, p as signJsonLd, r as signObject, s as doesActorOwnKey } from "./proof-5kT7OUPV.js";
|
|
7
|
+
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-CAY3OdLq.js";
|
|
8
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-C3NWWiTg.js";
|
|
9
9
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
10
10
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
11
11
|
import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
|
|
@@ -788,6 +788,12 @@ var FederationMetrics = class {
|
|
|
788
788
|
inboxProcessingDuration;
|
|
789
789
|
httpServerRequestCount;
|
|
790
790
|
httpServerRequestDuration;
|
|
791
|
+
queueTaskEnqueued;
|
|
792
|
+
queueTaskStarted;
|
|
793
|
+
queueTaskCompleted;
|
|
794
|
+
queueTaskFailed;
|
|
795
|
+
queueTaskDuration;
|
|
796
|
+
queueTaskInFlight;
|
|
791
797
|
constructor(meterProvider) {
|
|
792
798
|
const meter = meterProvider.getMeter(name, version);
|
|
793
799
|
this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
|
|
@@ -834,6 +840,46 @@ var FederationMetrics = class {
|
|
|
834
840
|
1e4
|
|
835
841
|
] }
|
|
836
842
|
});
|
|
843
|
+
this.queueTaskEnqueued = meter.createCounter("fedify.queue.task.enqueued", {
|
|
844
|
+
description: "Tasks Fedify enqueued for inbox, outbox, or fanout work.",
|
|
845
|
+
unit: "{task}"
|
|
846
|
+
});
|
|
847
|
+
this.queueTaskStarted = meter.createCounter("fedify.queue.task.started", {
|
|
848
|
+
description: "Tasks Fedify began processing as a queue worker.",
|
|
849
|
+
unit: "{task}"
|
|
850
|
+
});
|
|
851
|
+
this.queueTaskCompleted = meter.createCounter("fedify.queue.task.completed", {
|
|
852
|
+
description: "Queue tasks Fedify finished processing without throwing.",
|
|
853
|
+
unit: "{task}"
|
|
854
|
+
});
|
|
855
|
+
this.queueTaskFailed = meter.createCounter("fedify.queue.task.failed", {
|
|
856
|
+
description: "Queue tasks Fedify abandoned because processing threw.",
|
|
857
|
+
unit: "{task}"
|
|
858
|
+
});
|
|
859
|
+
this.queueTaskDuration = meter.createHistogram("fedify.queue.task.duration", {
|
|
860
|
+
description: "Duration of queue task processing in Fedify workers.",
|
|
861
|
+
unit: "ms",
|
|
862
|
+
advice: { explicitBucketBoundaries: [
|
|
863
|
+
5,
|
|
864
|
+
10,
|
|
865
|
+
25,
|
|
866
|
+
50,
|
|
867
|
+
75,
|
|
868
|
+
100,
|
|
869
|
+
250,
|
|
870
|
+
500,
|
|
871
|
+
750,
|
|
872
|
+
1e3,
|
|
873
|
+
2500,
|
|
874
|
+
5e3,
|
|
875
|
+
7500,
|
|
876
|
+
1e4
|
|
877
|
+
] }
|
|
878
|
+
});
|
|
879
|
+
this.queueTaskInFlight = meter.createUpDownCounter("fedify.queue.task.in_flight", {
|
|
880
|
+
description: "Queue tasks currently being processed in this Fedify process.",
|
|
881
|
+
unit: "{task}"
|
|
882
|
+
});
|
|
837
883
|
}
|
|
838
884
|
recordDelivery(inbox, durationMs, success, activityType) {
|
|
839
885
|
const deliveryAttributes = {
|
|
@@ -868,7 +914,85 @@ var FederationMetrics = class {
|
|
|
868
914
|
this.httpServerRequestCount.add(1, attributes);
|
|
869
915
|
this.httpServerRequestDuration.record(durationMs, attributes);
|
|
870
916
|
}
|
|
917
|
+
recordQueueTaskEnqueued(common, attempt) {
|
|
918
|
+
const attributes = buildQueueTaskAttributes(common);
|
|
919
|
+
attributes["fedify.queue.task.attempt"] = attempt;
|
|
920
|
+
this.queueTaskEnqueued.add(1, attributes);
|
|
921
|
+
}
|
|
922
|
+
recordQueueTaskStarted(common) {
|
|
923
|
+
this.queueTaskStarted.add(1, buildQueueTaskAttributes(common));
|
|
924
|
+
}
|
|
925
|
+
incrementQueueTaskInFlight(common) {
|
|
926
|
+
this.queueTaskInFlight.add(1, buildQueueTaskInFlightAttributes(common));
|
|
927
|
+
}
|
|
928
|
+
decrementQueueTaskInFlight(common) {
|
|
929
|
+
this.queueTaskInFlight.add(-1, buildQueueTaskInFlightAttributes(common));
|
|
930
|
+
}
|
|
931
|
+
recordQueueTaskOutcome(common, result, durationMs) {
|
|
932
|
+
const attributes = buildQueueTaskAttributes(common);
|
|
933
|
+
attributes["fedify.queue.task.result"] = result;
|
|
934
|
+
if (result === "completed") this.queueTaskCompleted.add(1, attributes);
|
|
935
|
+
else if (result === "failed") this.queueTaskFailed.add(1, attributes);
|
|
936
|
+
this.queueTaskDuration.record(durationMs, attributes);
|
|
937
|
+
}
|
|
871
938
|
};
|
|
939
|
+
function buildQueueTaskAttributes(common) {
|
|
940
|
+
const attributes = { "fedify.queue.role": common.role };
|
|
941
|
+
const backend = getQueueBackend(common.queue);
|
|
942
|
+
if (backend != null) attributes["fedify.queue.backend"] = backend;
|
|
943
|
+
const nativeRetrial = common.queue?.nativeRetrial;
|
|
944
|
+
if (typeof nativeRetrial === "boolean") attributes["fedify.queue.native_retrial"] = nativeRetrial;
|
|
945
|
+
if (common.activityType != null) attributes["activitypub.activity.type"] = common.activityType;
|
|
946
|
+
return attributes;
|
|
947
|
+
}
|
|
948
|
+
function buildQueueTaskInFlightAttributes(common) {
|
|
949
|
+
return buildQueueTaskAttributes({
|
|
950
|
+
role: common.role,
|
|
951
|
+
queue: common.queue
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Returns the constructor name of the given message queue, when it is a
|
|
956
|
+
* meaningful identifier. Used as a best-effort `fedify.queue.backend`
|
|
957
|
+
* attribute on queue task metrics; returns `undefined` for plain object
|
|
958
|
+
* literals (whose constructor is `Object`) so the attribute does not appear
|
|
959
|
+
* with a non-informative value.
|
|
960
|
+
* @since 2.3.0
|
|
961
|
+
*/
|
|
962
|
+
function getQueueBackend(queue) {
|
|
963
|
+
const name = queue?.constructor?.name;
|
|
964
|
+
if (name == null || name === "" || name === "Object") return void 0;
|
|
965
|
+
return name;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue.
|
|
969
|
+
*
|
|
970
|
+
* Both `Context.sendActivity()` and `OutboxContext.forwardActivity()` enqueue
|
|
971
|
+
* outbox messages with the same metric attributes (role, queue, activity
|
|
972
|
+
* type, attempt), so they share this helper rather than each defining a local
|
|
973
|
+
* closure.
|
|
974
|
+
* @since 2.3.0
|
|
975
|
+
*/
|
|
976
|
+
function recordOutboxEnqueue(meterProvider, outboxQueue, message) {
|
|
977
|
+
getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
|
|
978
|
+
role: "outbox",
|
|
979
|
+
queue: outboxQueue,
|
|
980
|
+
activityType: message.activityType
|
|
981
|
+
}, message.attempt);
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Whether the given thrown value is an `AbortError`.
|
|
985
|
+
*
|
|
986
|
+
* `processQueuedTask` distinguishes aborted tasks (recorded as
|
|
987
|
+
* `fedify.queue.task.result=aborted`) from other failures so that backend
|
|
988
|
+
* shutdown signals do not inflate the `fedify.queue.task.failed` counter.
|
|
989
|
+
* @since 2.3.0
|
|
990
|
+
*/
|
|
991
|
+
function isAbortError(error) {
|
|
992
|
+
if (error == null || typeof error !== "object") return false;
|
|
993
|
+
const name = error.name;
|
|
994
|
+
return typeof name === "string" && name === "AbortError";
|
|
995
|
+
}
|
|
872
996
|
const KNOWN_HTTP_METHODS = new Set([
|
|
873
997
|
"CONNECT",
|
|
874
998
|
"DELETE",
|
|
@@ -990,6 +1114,11 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
990
1114
|
});
|
|
991
1115
|
throw error;
|
|
992
1116
|
}
|
|
1117
|
+
getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
|
|
1118
|
+
role: "inbox",
|
|
1119
|
+
queue,
|
|
1120
|
+
activityType: getTypeId(activity).href
|
|
1121
|
+
}, 0);
|
|
993
1122
|
logger.info("Activity {activityId} is enqueued.", {
|
|
994
1123
|
activityId: activity.id?.href,
|
|
995
1124
|
activity: json,
|
|
@@ -3104,78 +3233,123 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3104
3233
|
processQueuedTask(contextData, message) {
|
|
3105
3234
|
const tracer = this._getTracer();
|
|
3106
3235
|
const extractedContext = propagation.extract(context.active(), message.traceContext);
|
|
3236
|
+
const meter = getFederationMetrics(this.meterProvider);
|
|
3107
3237
|
return withContext({ messageId: message.id }, async () => {
|
|
3108
|
-
if (message.type === "fanout")
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3238
|
+
if (message.type === "fanout") {
|
|
3239
|
+
const common = {
|
|
3240
|
+
role: "fanout",
|
|
3241
|
+
queue: this.fanoutQueue,
|
|
3242
|
+
activityType: message.activityType
|
|
3243
|
+
};
|
|
3244
|
+
await tracer.startActiveSpan("activitypub.fanout", {
|
|
3245
|
+
kind: SpanKind.CONSUMER,
|
|
3246
|
+
attributes: { "activitypub.activity.type": message.activityType }
|
|
3247
|
+
}, extractedContext, async (span) => {
|
|
3248
|
+
const spanCtx = span.spanContext();
|
|
3249
|
+
return await withContext({
|
|
3250
|
+
traceId: spanCtx.traceId,
|
|
3251
|
+
spanId: spanCtx.spanId
|
|
3252
|
+
}, async () => {
|
|
3253
|
+
if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
|
|
3254
|
+
meter.recordQueueTaskStarted(common);
|
|
3255
|
+
meter.incrementQueueTaskInFlight(common);
|
|
3256
|
+
const startedAt = performance.now();
|
|
3257
|
+
let outcome = "completed";
|
|
3258
|
+
try {
|
|
3259
|
+
await this.#listenFanoutMessage(contextData, message);
|
|
3260
|
+
} catch (e) {
|
|
3261
|
+
const aborted = isAbortError(e);
|
|
3262
|
+
outcome = aborted ? "aborted" : "failed";
|
|
3263
|
+
if (!aborted) span.setStatus({
|
|
3264
|
+
code: SpanStatusCode.ERROR,
|
|
3265
|
+
message: String(e)
|
|
3266
|
+
});
|
|
3267
|
+
throw e;
|
|
3268
|
+
} finally {
|
|
3269
|
+
meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
|
|
3270
|
+
meter.decrementQueueTaskInFlight(common);
|
|
3271
|
+
span.end();
|
|
3272
|
+
}
|
|
3273
|
+
});
|
|
3129
3274
|
});
|
|
3130
|
-
})
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
spanId: spanCtx.spanId
|
|
3142
|
-
}, async () => {
|
|
3143
|
-
if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
|
|
3144
|
-
try {
|
|
3145
|
-
await this.#listenOutboxMessage(contextData, message, span);
|
|
3146
|
-
} catch (e) {
|
|
3147
|
-
span.setStatus({
|
|
3148
|
-
code: SpanStatusCode.ERROR,
|
|
3149
|
-
message: String(e)
|
|
3150
|
-
});
|
|
3151
|
-
throw e;
|
|
3152
|
-
} finally {
|
|
3153
|
-
span.end();
|
|
3275
|
+
} else if (message.type === "outbox") {
|
|
3276
|
+
const common = {
|
|
3277
|
+
role: "outbox",
|
|
3278
|
+
queue: this.outboxQueue,
|
|
3279
|
+
activityType: message.activityType
|
|
3280
|
+
};
|
|
3281
|
+
await tracer.startActiveSpan("activitypub.outbox", {
|
|
3282
|
+
kind: SpanKind.CONSUMER,
|
|
3283
|
+
attributes: {
|
|
3284
|
+
"activitypub.activity.type": message.activityType,
|
|
3285
|
+
"activitypub.activity.retries": message.attempt
|
|
3154
3286
|
}
|
|
3287
|
+
}, extractedContext, async (span) => {
|
|
3288
|
+
const spanCtx = span.spanContext();
|
|
3289
|
+
return await withContext({
|
|
3290
|
+
traceId: spanCtx.traceId,
|
|
3291
|
+
spanId: spanCtx.spanId
|
|
3292
|
+
}, async () => {
|
|
3293
|
+
if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
|
|
3294
|
+
meter.recordQueueTaskStarted(common);
|
|
3295
|
+
meter.incrementQueueTaskInFlight(common);
|
|
3296
|
+
const startedAt = performance.now();
|
|
3297
|
+
let outcome = "completed";
|
|
3298
|
+
try {
|
|
3299
|
+
await this.#listenOutboxMessage(contextData, message, span);
|
|
3300
|
+
} catch (e) {
|
|
3301
|
+
const aborted = isAbortError(e);
|
|
3302
|
+
outcome = aborted ? "aborted" : "failed";
|
|
3303
|
+
if (!aborted) span.setStatus({
|
|
3304
|
+
code: SpanStatusCode.ERROR,
|
|
3305
|
+
message: String(e)
|
|
3306
|
+
});
|
|
3307
|
+
throw e;
|
|
3308
|
+
} finally {
|
|
3309
|
+
meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
|
|
3310
|
+
meter.decrementQueueTaskInFlight(common);
|
|
3311
|
+
span.end();
|
|
3312
|
+
}
|
|
3313
|
+
});
|
|
3155
3314
|
});
|
|
3156
|
-
})
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3315
|
+
} else if (message.type === "inbox") {
|
|
3316
|
+
const common = {
|
|
3317
|
+
role: "inbox",
|
|
3318
|
+
queue: this.inboxQueue
|
|
3319
|
+
};
|
|
3320
|
+
await tracer.startActiveSpan("activitypub.inbox", {
|
|
3321
|
+
kind: SpanKind.CONSUMER,
|
|
3322
|
+
attributes: { "activitypub.shared_inbox": message.identifier == null }
|
|
3323
|
+
}, extractedContext, async (span) => {
|
|
3324
|
+
const spanCtx = span.spanContext();
|
|
3325
|
+
return await withContext({
|
|
3326
|
+
traceId: spanCtx.traceId,
|
|
3327
|
+
spanId: spanCtx.spanId
|
|
3328
|
+
}, async () => {
|
|
3329
|
+
meter.recordQueueTaskStarted(common);
|
|
3330
|
+
meter.incrementQueueTaskInFlight(common);
|
|
3331
|
+
const startedAt = performance.now();
|
|
3332
|
+
let outcome = "completed";
|
|
3333
|
+
try {
|
|
3334
|
+
await this.#listenInboxMessage(contextData, message, span, (activityType) => {
|
|
3335
|
+
common.activityType = activityType;
|
|
3336
|
+
});
|
|
3337
|
+
} catch (e) {
|
|
3338
|
+
const aborted = isAbortError(e);
|
|
3339
|
+
outcome = aborted ? "aborted" : "failed";
|
|
3340
|
+
if (!aborted) span.setStatus({
|
|
3341
|
+
code: SpanStatusCode.ERROR,
|
|
3342
|
+
message: String(e)
|
|
3343
|
+
});
|
|
3344
|
+
throw e;
|
|
3345
|
+
} finally {
|
|
3346
|
+
meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
|
|
3347
|
+
meter.decrementQueueTaskInFlight(common);
|
|
3348
|
+
span.end();
|
|
3349
|
+
}
|
|
3350
|
+
});
|
|
3177
3351
|
});
|
|
3178
|
-
}
|
|
3352
|
+
}
|
|
3179
3353
|
});
|
|
3180
3354
|
}
|
|
3181
3355
|
async #listenFanoutMessage(data, message) {
|
|
@@ -3332,10 +3506,19 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3332
3506
|
...logData,
|
|
3333
3507
|
error
|
|
3334
3508
|
});
|
|
3335
|
-
|
|
3509
|
+
const retryMessage = {
|
|
3336
3510
|
...message,
|
|
3337
3511
|
attempt: message.attempt + 1
|
|
3338
|
-
}
|
|
3512
|
+
};
|
|
3513
|
+
const { outboxQueue } = this;
|
|
3514
|
+
if (outboxQueue != null) {
|
|
3515
|
+
await outboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
3516
|
+
getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
|
|
3517
|
+
role: "outbox",
|
|
3518
|
+
queue: outboxQueue,
|
|
3519
|
+
activityType: retryMessage.activityType
|
|
3520
|
+
}, retryMessage.attempt);
|
|
3521
|
+
}
|
|
3339
3522
|
} else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
|
|
3340
3523
|
...logData,
|
|
3341
3524
|
error
|
|
@@ -3344,7 +3527,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3344
3527
|
}
|
|
3345
3528
|
logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
|
|
3346
3529
|
}
|
|
3347
|
-
async #listenInboxMessage(ctxData, message, span) {
|
|
3530
|
+
async #listenInboxMessage(ctxData, message, span, onActivityType) {
|
|
3348
3531
|
const logger = getLogger([
|
|
3349
3532
|
"fedify",
|
|
3350
3533
|
"federation",
|
|
@@ -3358,7 +3541,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3358
3541
|
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
3359
3542
|
}
|
|
3360
3543
|
const activity = await Activity.fromJsonLd(message.activity, context);
|
|
3361
|
-
|
|
3544
|
+
const activityType = getTypeId(activity).href;
|
|
3545
|
+
span.setAttribute("activitypub.activity.type", activityType);
|
|
3546
|
+
onActivityType?.(activityType);
|
|
3362
3547
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
3363
3548
|
const cacheKey = activity.id == null ? null : [
|
|
3364
3549
|
...this.kvPrefixes.activityIdempotence,
|
|
@@ -3386,7 +3571,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3386
3571
|
});
|
|
3387
3572
|
span.setStatus({
|
|
3388
3573
|
code: SpanStatusCode.ERROR,
|
|
3389
|
-
message: `Unsupported activity type: ${
|
|
3574
|
+
message: `Unsupported activity type: ${activityType}`
|
|
3390
3575
|
});
|
|
3391
3576
|
span.end();
|
|
3392
3577
|
return;
|
|
@@ -3394,7 +3579,6 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3394
3579
|
const { class: cls, listener } = dispatched;
|
|
3395
3580
|
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
3396
3581
|
try {
|
|
3397
|
-
const activityType = getTypeId(activity).href;
|
|
3398
3582
|
const started = performance.now();
|
|
3399
3583
|
try {
|
|
3400
3584
|
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
|
|
@@ -3439,10 +3623,19 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3439
3623
|
activity: message.activity,
|
|
3440
3624
|
recipient: message.identifier
|
|
3441
3625
|
});
|
|
3442
|
-
|
|
3626
|
+
const retryMessage = {
|
|
3443
3627
|
...message,
|
|
3444
3628
|
attempt: message.attempt + 1
|
|
3445
|
-
}
|
|
3629
|
+
};
|
|
3630
|
+
const { inboxQueue } = this;
|
|
3631
|
+
if (inboxQueue != null) {
|
|
3632
|
+
await inboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
3633
|
+
getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
|
|
3634
|
+
role: "inbox",
|
|
3635
|
+
queue: inboxQueue,
|
|
3636
|
+
activityType
|
|
3637
|
+
}, retryMessage.attempt);
|
|
3638
|
+
}
|
|
3446
3639
|
} else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
3447
3640
|
error,
|
|
3448
3641
|
activityId: activity.id?.href,
|
|
@@ -3631,9 +3824,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3631
3824
|
});
|
|
3632
3825
|
}
|
|
3633
3826
|
const { outboxQueue } = this;
|
|
3634
|
-
if (outboxQueue.enqueueMany == null) {
|
|
3635
|
-
const
|
|
3636
|
-
|
|
3827
|
+
if (outboxQueue.enqueueMany == null || orderingKey != null) {
|
|
3828
|
+
const errors = (await Promise.allSettled(messages.map(async (m) => {
|
|
3829
|
+
await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
|
|
3830
|
+
recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
|
|
3831
|
+
}))).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3637
3832
|
if (errors.length > 0) {
|
|
3638
3833
|
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
3639
3834
|
activityId: activity.id.href,
|
|
@@ -3642,25 +3837,17 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3642
3837
|
if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
|
|
3643
3838
|
throw errors[0];
|
|
3644
3839
|
}
|
|
3645
|
-
} else
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
logger.error("Failed to enqueue activity {activityId} to send later: {
|
|
3840
|
+
} else {
|
|
3841
|
+
try {
|
|
3842
|
+
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
3843
|
+
} catch (error) {
|
|
3844
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
3650
3845
|
activityId: activity.id.href,
|
|
3651
|
-
|
|
3846
|
+
error
|
|
3652
3847
|
});
|
|
3653
|
-
|
|
3654
|
-
throw errors[0];
|
|
3848
|
+
throw error;
|
|
3655
3849
|
}
|
|
3656
|
-
|
|
3657
|
-
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
3658
|
-
} catch (error) {
|
|
3659
|
-
logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
3660
|
-
activityId: activity.id.href,
|
|
3661
|
-
error
|
|
3662
|
-
});
|
|
3663
|
-
throw error;
|
|
3850
|
+
for (const m of messages) recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
|
|
3664
3851
|
}
|
|
3665
3852
|
}
|
|
3666
3853
|
fetch(request, options) {
|
|
@@ -4476,6 +4663,11 @@ var ContextImpl = class ContextImpl {
|
|
|
4476
4663
|
};
|
|
4477
4664
|
if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
|
|
4478
4665
|
await this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
|
|
4666
|
+
getFederationMetrics(this.federation.meterProvider).recordQueueTaskEnqueued({
|
|
4667
|
+
role: "fanout",
|
|
4668
|
+
queue: this.federation.fanoutQueue,
|
|
4669
|
+
activityType: message.activityType
|
|
4670
|
+
}, 0);
|
|
4479
4671
|
return true;
|
|
4480
4672
|
}
|
|
4481
4673
|
async *getFollowers(identifier) {
|
|
@@ -4606,6 +4798,7 @@ var ContextImpl = class ContextImpl {
|
|
|
4606
4798
|
kvPrefixes: this.federation.kvPrefixes,
|
|
4607
4799
|
queue: this.federation.inboxQueue,
|
|
4608
4800
|
span,
|
|
4801
|
+
meterProvider: this.federation.meterProvider,
|
|
4609
4802
|
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
|
4610
4803
|
idempotencyStrategy: this.federation.idempotencyStrategy
|
|
4611
4804
|
});
|
|
@@ -4855,8 +5048,10 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
4855
5048
|
}
|
|
4856
5049
|
const { outboxQueue } = ctx.federation;
|
|
4857
5050
|
if (outboxQueue.enqueueMany == null || orderingKey != null) {
|
|
4858
|
-
const
|
|
4859
|
-
|
|
5051
|
+
const errors = (await Promise.allSettled(messages.map(async (m) => {
|
|
5052
|
+
await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
|
|
5053
|
+
recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
|
|
5054
|
+
}))).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4860
5055
|
if (errors.length > 0) {
|
|
4861
5056
|
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
4862
5057
|
activityId: ctx.activityId,
|
|
@@ -4865,14 +5060,17 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
4865
5060
|
if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${ctx.activityId} to forward later.`);
|
|
4866
5061
|
throw errors[0];
|
|
4867
5062
|
}
|
|
4868
|
-
} else
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
activityId
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
5063
|
+
} else {
|
|
5064
|
+
try {
|
|
5065
|
+
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
5066
|
+
} catch (error) {
|
|
5067
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
5068
|
+
activityId: ctx.activityId,
|
|
5069
|
+
error
|
|
5070
|
+
});
|
|
5071
|
+
throw error;
|
|
5072
|
+
}
|
|
5073
|
+
for (const m of messages) recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
|
|
4876
5074
|
}
|
|
4877
5075
|
return true;
|
|
4878
5076
|
}
|