Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { NextResponse } from 'next/server';
import { captureException } from '@sentry/nextjs';
import { db } from '@/lib/drizzle';
import { CRON_SECRET } from '@/lib/config.server';
import { sql } from 'drizzle-orm';
import { format } from 'date-fns';

if (!CRON_SECRET) {
throw new Error('CRON_SECRET is not configured in environment variables');
}

/**
* Provisions the current month and two months ahead so inserts route into a
* bounded monthly partition window.
*/
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${CRON_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

const now = new Date();
const created: string[] = [];
const errors: string[] = [];

for (let offset = 0; offset <= 2; offset++) {
const target = new Date(now.getFullYear(), now.getMonth() + offset, 1);
const nextMonth = new Date(target.getFullYear(), target.getMonth() + 1, 1);
const name = `model_experiment_request_${format(target, 'yyyy_MM')}`;

try {
await db.execute(
sql.raw(
`CREATE TABLE IF NOT EXISTS "${name}" PARTITION OF "model_experiment_request" FOR VALUES FROM ('${format(target, 'yyyy-MM-dd')}') TO ('${format(nextMonth, 'yyyy-MM-dd')}')`
)
);
created.push(name);
} catch (error) {
const message = `Failed to create partition ${name}: ${error instanceof Error ? error.message : String(error)}`;
console.error(`[model-experiment-request-partition-maintenance] ${message}`);
captureException(error, {
tags: { source: 'model-experiment-request-partition-maintenance', partition: name },
});
errors.push(message);
}
}

console.log(
`[model-experiment-request-partition-maintenance] created=[${created.join(', ')}] errors=${errors.length}`
);

return NextResponse.json({
success: errors.length === 0,
created,
errors,
});
}
4 changes: 4 additions & 0 deletions apps/web/vercel.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
"path": "/api/cron/exa-partition-maintenance",
"schedule": "0 0 1 * *"
},
{
"path": "/api/cron/model-experiment-request-partition-maintenance",
"schedule": "0 0 1 * *"
},
{
"path": "/api/cron/cleanup-free-model-usage",
"schedule": "0 * * * *"
Expand Down
33 changes: 33 additions & 0 deletions packages/db/src/migrations/0142_dashing_blue_marvel.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
DROP TABLE "model_experiment_request";
--> statement-breakpoint
CREATE TABLE "model_experiment_request" (
"usage_id" uuid NOT NULL,
"variant_version_id" uuid NOT NULL,
"allocation_subject" text NOT NULL,
"client_request_id" text,
"request_kind" text NOT NULL,
"request_body_sha256" text NOT NULL,
"was_truncated" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "model_experiment_request_usage_id_created_at_pk" PRIMARY KEY("usage_id","created_at"),
CONSTRAINT "model_experiment_request_allocation_subject_valid" CHECK ("model_experiment_request"."allocation_subject" IN ('user', 'machine', 'ip')),
CONSTRAINT "model_experiment_request_request_kind_valid" CHECK ("model_experiment_request"."request_kind" IN ('chat_completions', 'messages', 'responses')),
CONSTRAINT "model_experiment_request_request_body_sha256_format" CHECK ("model_experiment_request"."request_body_sha256" ~ '^[0-9a-f]{64}$' OR "model_experiment_request"."request_body_sha256" IN ('__failed__', '__deleted__'))
) PARTITION BY RANGE ("created_at");
--> statement-breakpoint
CREATE TABLE "model_experiment_request_2026_05" PARTITION OF "model_experiment_request"
FOR VALUES FROM ('2026-05-01') TO ('2026-06-01');
--> statement-breakpoint
CREATE TABLE "model_experiment_request_2026_06" PARTITION OF "model_experiment_request"
FOR VALUES FROM ('2026-06-01') TO ('2026-07-01');
--> statement-breakpoint
CREATE TABLE "model_experiment_request_2026_07" PARTITION OF "model_experiment_request"
FOR VALUES FROM ('2026-07-01') TO ('2026-08-01');
--> statement-breakpoint
ALTER TABLE "model_experiment_request" ADD CONSTRAINT "model_experiment_request_usage_id_microdollar_usage_id_fk" FOREIGN KEY ("usage_id") REFERENCES "public"."microdollar_usage"("id") ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "model_experiment_request" ADD CONSTRAINT "model_experiment_request_variant_version_id_model_experiment_variant_version_id_fk" FOREIGN KEY ("variant_version_id") REFERENCES "public"."model_experiment_variant_version"("id") ON DELETE no action ON UPDATE no action;
--> statement-breakpoint
CREATE INDEX "IDX_model_experiment_request_variant_version_created_at" ON "model_experiment_request" USING btree ("variant_version_id","created_at");
--> statement-breakpoint
CREATE INDEX "IDX_model_experiment_request_client_request_id" ON "model_experiment_request" USING btree ("client_request_id") WHERE "model_experiment_request"."client_request_id" is not null;
Loading