mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 21:07:40 +01:00
perf(server): bound gateway expiry deadline discovery
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
75332b9641
commit
c5c53fc43f
7 files changed
+57
-8
No files matched your search
@@ -26,7 +26,9 @@ reconstructs existing rows but does not provide continuous replica discovery.
|
||||
|
||||
## Worker contract
|
||||
|
||||
`nextCredentialExpiryAt` reads the earliest non-null expiry across both tables.
|
||||
`nextCredentialExpiryAt` reads one earliest non-null expiry from each table using
|
||||
expiry-first indexes, then compares those at most two values. The migration adds
|
||||
the session expiry index; the token expiry index already exists.
|
||||
An empty credential store or retained non-expiring tokens returns no deadline.
|
||||
`registerGatewayCredentialExpiryWork` supplies cleanup and deadline selection to
|
||||
the shared `registerDeadlineWork` helper. Provider and authentication behavior
|
||||
@@ -47,6 +49,12 @@ in-flight work.
|
||||
|
||||
## Evidence and limits
|
||||
|
||||
The concurrent session index runs through the migration executor's existing
|
||||
per-file top-level path. Initial application and repeat application were tested.
|
||||
A PostgreSQL plan with 20,000 sessions and 20,000 tokens, including 19,000
|
||||
non-expiring tokens, used both expiry indexes and read one row from each.
|
||||
This establishes bounded lookup on that fixture, not production latency.
|
||||
|
||||
The new PostgreSQL suite exercises real session/token creation, configured idle
|
||||
state, non-expiring history, expiry ordering, revoked-token cleanup, outer commit
|
||||
and rollback, startup reconstruction, a backlog larger than one cleanup batch,
|
||||
|
||||
@@ -504,6 +504,7 @@ const MIGRATIONS_WITH_TOP_LEVEL_STATEMENTS = new Set([
|
||||
"0332_little_night_nurse.sql",
|
||||
"0345_luxuriant_carmella_unuscione.sql",
|
||||
"0369_late_logan.sql",
|
||||
"0378_mean_scream.sql",
|
||||
]);
|
||||
|
||||
async function applyPendingMigrationsManually(
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS "tool_gateway_sessions_expiry_idx" ON "tool_gateway_sessions" USING btree ("expires_at");
|
||||
+33
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "406521f8-5352-415b-805d-786854381e03",
|
||||
"prevId": "9c1b4cac-52f1-4c6e-89b3-c9a7816016c7",
|
||||
"id": "01c4455a-e59c-43e6-940b-09b9c76171d8",
|
||||
"prevId": "a0fcd9b8-f125-4985-8795-f567466b9aef",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
@@ -28508,6 +28508,13 @@
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"checkout_name": {
|
||||
"name": "checkout_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"object_key": {
|
||||
"name": "object_key",
|
||||
"type": "text",
|
||||
@@ -28601,8 +28608,8 @@
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
},
|
||||
"execution_workspace_restore_points_live_generation_uniq": {
|
||||
"name": "execution_workspace_restore_points_live_generation_uniq",
|
||||
"execution_workspace_restore_points_live_status_uniq": {
|
||||
"name": "execution_workspace_restore_points_live_status_uniq",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "execution_workspace_id",
|
||||
@@ -28615,10 +28622,16 @@
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "checkout_name",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"where": "\"execution_workspace_restore_points\".\"status\" <> 'deleted'",
|
||||
"where": "\"execution_workspace_restore_points\".\"status\" in ('pending', 'active', 'expiring')",
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
@@ -55184,6 +55197,21 @@
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
},
|
||||
"tool_gateway_sessions_expiry_idx": {
|
||||
"name": "tool_gateway_sessions_expiry_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "expires_at",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
},
|
||||
"tool_gateway_sessions_run_idx": {
|
||||
"name": "tool_gateway_sessions_run_idx",
|
||||
"columns": [
|
||||
+7
@@ -2633,6 +2633,13 @@
|
||||
"when": 1792790134086,
|
||||
"tag": "0377_clear_settled_native_run_process_identity",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 378,
|
||||
"version": "7",
|
||||
"when": 1792861534317,
|
||||
"tag": "0378_mean_scream",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -710,6 +710,7 @@ export const toolGatewaySessions = pgTable(
|
||||
uniqueIndex("tool_gateway_sessions_token_hash_uq").on(table.tokenHash),
|
||||
index("tool_gateway_sessions_company_agent_idx").on(table.companyId, table.agentId),
|
||||
index("tool_gateway_sessions_company_expires_idx").on(table.companyId, table.expiresAt),
|
||||
index("tool_gateway_sessions_expiry_idx").on(table.expiresAt),
|
||||
index("tool_gateway_sessions_run_idx").on(table.companyId, table.runId),
|
||||
index("tool_gateway_sessions_issue_idx").on(table.companyId, table.issueId),
|
||||
index("tool_gateway_sessions_gateway_idx").on(table.companyId, table.gatewayId),
|
||||
|
||||
@@ -11608,9 +11608,12 @@ export function createToolGatewayService(
|
||||
async nextCredentialExpiryAt(): Promise<number | null> {
|
||||
const [row] = await db.execute<{ at: string | Date | null }>(sql`
|
||||
select min(expires_at) as at from (
|
||||
select ${toolMcpGatewayTokens.expiresAt} as expires_at from ${toolMcpGatewayTokens}
|
||||
(select ${toolMcpGatewayTokens.expiresAt} as expires_at from ${toolMcpGatewayTokens}
|
||||
where ${toolMcpGatewayTokens.expiresAt} is not null
|
||||
order by ${toolMcpGatewayTokens.expiresAt} limit 1)
|
||||
union all
|
||||
select ${toolGatewaySessions.expiresAt} as expires_at from ${toolGatewaySessions}
|
||||
(select ${toolGatewaySessions.expiresAt} as expires_at from ${toolGatewaySessions}
|
||||
order by ${toolGatewaySessions.expiresAt} limit 1)
|
||||
) expiries
|
||||
`);
|
||||
return row?.at == null ? null : new Date(row.at).getTime();
|
||||
|
||||
Reference in new issue
Block a user