mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
feat(storage): migrate config, dedup and delivery state to D1
- Move oversized queue payloads from KV to R2 (PAYLOAD binding, webhooks/YYYY/MM/DD/*.json, KV queue:payload:* fallback)
- Persist routes/groups to D1 (d1_routes/d1_groups) with memory -> KV -> D1 three-tier cache, seeded from legacy KV config keys
- Move webhook dedup (dedup_keys), delivery state (delivery_state) and message tracking (message_tracking) to D1 via canUseD1 probe with automatic KV fallback
- Batch send_logs inserts (recordSendBatch) and add group_id/ts index
- Add storage-prune scheduled task for expired dedup/state/tracking rows
- Add TTL to invite:group:{id} index and audit all ephemeral KV keys
- Add D1 indexes for the new tables
- Sync AGENTS.md, README.md/zh and docs/ (en/zh) with the new storage layout
This commit is contained in:
parent
2e1b0f022e
commit
25ebae4ae5
46 changed files with 1450 additions and 117 deletions
|
|
@ -3,13 +3,13 @@ import { getHeader, readRawBody, setResponseStatus } from "h3";
|
|||
import type { Env } from "./types";
|
||||
import { detectProvider } from "./providers";
|
||||
import { dispatchEvent } from "./core/dispatch";
|
||||
import { loadConfig } from "./config";
|
||||
import { loadConfig, initConfigStore } from "./config";
|
||||
import { loadGroups, ensureInstallationGroup } from "./web/groups";
|
||||
import { getTenantSecret } from "./web/tenants";
|
||||
import { recordAudit } from "./lib/audit";
|
||||
import { cfEnv, cfWaitUntil, headersFrom } from "./cf";
|
||||
import { log } from "./lib/log";
|
||||
import { deliveryKey, kvIdempotencyStore } from "./lib/idempotency";
|
||||
import { deliveryKey, idempotencyStore } from "./lib/idempotency";
|
||||
import { newCorrelationId } from "./lib/correlation";
|
||||
import { enqueueWebhook, type DeliveryMessage } from "./queue/delivery";
|
||||
|
||||
|
|
@ -37,6 +37,7 @@ export async function processWebhook(
|
|||
): Promise<WebhookResult> {
|
||||
const requestId = newCorrelationId();
|
||||
let effectiveEnv = env;
|
||||
initConfigStore(env);
|
||||
const groups = await loadGroups(env.KV);
|
||||
if (tenantId) {
|
||||
if (!groups.some((g) => g.id === tenantId)) {
|
||||
|
|
@ -124,7 +125,7 @@ export async function processWebhook(
|
|||
// Dedup via the idempotency store: a provider/tenant-scoped key means
|
||||
// different accounts may reuse a delivery id without colliding, while
|
||||
// retries of the same delivery never dispatch twice.
|
||||
const store = kvIdempotencyStore(env.KV);
|
||||
const store = idempotencyStore(env.DB, env.KV);
|
||||
const key = deliveryKey(provider.id, tenantId, event.deliveryId);
|
||||
if (!(await store.claim(key, 120))) {
|
||||
return { status: 200, body: { ok: true, duplicate: true, requestId } };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue