mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-24 01:41:42 +02:00
Merge reviewed credential contention handling into accounting
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
3f8a95f8a4
5 files changed
+81
-7
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE } from "@paperclipai/adapter-utils/workspace-restore-merge";
|
||||
import { withAccountHomeSecretMutationLock } from "@paperclipai/adapter-codex-local/server";
|
||||
import { syncConnectionCredentialBindings } from "./connection-credential-bindings.js";
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
@@ -861,6 +862,18 @@ export function aiConnectionService(db: Db) {
|
||||
if (recovered) await quotaCredentialRecovery(row.connection.companyId, row.grant.id).clear()
|
||||
.catch(error => logger.warn({ err: error, grantId: row.grant.id }, "Saved runtime credential recovery cleanup pending"));
|
||||
return value;
|
||||
}).catch(error => {
|
||||
// Drizzle wraps Postgres errors in `cause`. Contention is a temporary
|
||||
// pre-provider wait, not evidence that this account needs reconnecting.
|
||||
let current: unknown = error;
|
||||
for (let depth = 0; depth < 4 && current && typeof current === "object"; depth += 1) {
|
||||
const value = current as { code?: unknown; cause?: unknown };
|
||||
if (value.code === WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE || value.code === "55P03") {
|
||||
throw unprocessable("AI credentials are being updated. This execution will retry automatically.", { code: "ai_connection_busy" });
|
||||
}
|
||||
current = value.cause;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16375,9 +16375,8 @@ export function heartbeatService(
|
||||
.then((rows) => rows[0] ?? null);
|
||||
}
|
||||
|
||||
// No code path raises the `ai_connection_busy` error any more. This
|
||||
// function stays because a stored run row can still carry that error code
|
||||
// from an earlier release.
|
||||
// Credential rotation can briefly contend with a fresh runtime read. Keep
|
||||
// the task on its automatic pre-provider retry path while the lock clears.
|
||||
async function finalizeAiConnectionBusyDeferral(
|
||||
run: typeof heartbeatRuns.$inferSelect,
|
||||
error: HttpError,
|
||||
|
||||
Reference in new issue
Block a user