feat(collection): 采集箱开发

This commit is contained in:
R524809
2026-09-04 17:32:28 +08:00
parent edf7939963
commit 87db74fb89
16 changed files with 452 additions and 50 deletions
+19 -8
View File
@@ -33,23 +33,34 @@ const objectStorage = new S3Client({
},
});
const mediaUploadCleanup = new MediaUploadCleanup(database, objectStorage);
type StoreVerificationJob = OutboxJob & { payload: { store_id: string; operation_id: string; secret_id?: string } };
const worker = new Worker<OutboxJob>(
'atlas-dispatch',
async (job) => {
if (job.name === 'store_credential_verification.requested') {
await verifyStoreCredentials(database, job.data);
await verifyStoreCredentials(database, job.data as OutboxJob & { payload: { store_id: string; operation_id: string; secret_id?: string } });
} else if (job.name === 'collection.cleanup.requested') {
await cleanupCollection(database, job.data as OutboxJob & { payload: { operation_id: string; collection_item_ids: string[] } });
}
},
{ connection, concurrency: 5 },
);
async function cleanupCollection(database: Database, job: OutboxJob & { payload: { operation_id: string; collection_item_ids: string[] } }) {
await database.workspaceTransaction(job.workspaceId, async (tx) => {
await tx.query(`UPDATE atlas.operations SET status = 'running', started_at = coalesce(started_at, now()), attempt_count = attempt_count + 1 WHERE id = $1 AND status = 'queued'`, [job.payload.operation_id]);
await tx.query(`UPDATE atlas.collection_asset_transfers SET status = 'cancelled', updated_at = now(), completed_at = now() WHERE collection_item_id = ANY($1::uuid[]) AND status IN ('queued', 'running')`, [job.payload.collection_item_ids]);
await tx.query(`UPDATE atlas.operations SET status = 'succeeded', completed_at = now(), result = jsonb_build_object('cancelled_transfer_count', 0) WHERE id = $1 AND status IN ('queued', 'running')`, [job.payload.operation_id]);
});
}
worker.on('failed', (job, error) => {
if (!job || job.attemptsMade < (job.opts.attempts ?? 1)) return;
void markUnavailable(database, job.data, error);
if (!job || job.attemptsMade < (job.opts.attempts ?? 1) || job.name !== 'store_credential_verification.requested') return;
void markUnavailable(database, job.data as StoreVerificationJob, error);
});
async function verifyStoreCredentials(database: Database, job: OutboxJob) {
async function verifyStoreCredentials(database: Database, job: StoreVerificationJob) {
const source = await database.workspaceTransaction(
job.workspaceId,
async (tx) => {
@@ -98,7 +109,7 @@ async function verifyStoreCredentials(database: Database, job: OutboxJob) {
}
}
async function cancelStaleOperation(database: Database, job: OutboxJob) {
async function cancelStaleOperation(database: Database, job: StoreVerificationJob) {
await database.workspaceTransaction(job.workspaceId, (tx) =>
tx.query(
`UPDATE atlas.operations SET status = 'cancelled', completed_at = now(),
@@ -111,7 +122,7 @@ async function cancelStaleOperation(database: Database, job: OutboxJob) {
async function completeVerification(
database: Database,
job: OutboxJob,
job: StoreVerificationJob,
valid: boolean,
rejectedStatus?: 401 | 403,
) {
@@ -175,7 +186,7 @@ async function completeVerification(
async function markRequestRejected(
database: Database,
job: OutboxJob,
job: StoreVerificationJob,
status: number,
) {
await database.workspaceTransaction(job.workspaceId, async (tx) => {
@@ -205,7 +216,7 @@ async function markRequestRejected(
async function markUnavailable(
database: Database,
job: OutboxJob,
job: StoreVerificationJob,
_error: Error,
) {
await database.workspaceTransaction(job.workspaceId, async (tx) => {
+1 -1
View File
@@ -5,7 +5,7 @@ export type OutboxJob = {
eventId: string;
workspaceId: string;
eventType: string;
payload: { store_id: string; operation_id: string; secret_id?: string };
payload: Record<string, unknown>;
};
type EventRow = Omit<OutboxJob, 'eventId' | 'workspaceId' | 'eventType'> & {