feat(category): 类目树、属性、属性字典维护,新增系统管理员管理类目数据
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import type { Database, DatabaseTransaction } from '@atlas/database';
|
||||
|
||||
type Candidate = { scope: 'tree' | 'attributes' | 'dictionary'; scope_key: string;
|
||||
category_id: string | null; attribute_id: string | null };
|
||||
|
||||
/** 定时任务逐平台限量排队,避免启动时一次扫完全部类目和大字典。 */
|
||||
export class PlatformCatalogScheduler {
|
||||
public constructor(private readonly database: Database) {}
|
||||
|
||||
public async run() {
|
||||
const sources = await this.database.query<{ platform_id: string }>(
|
||||
`SELECT source.platform_id FROM atlas.platform_catalog_sources source
|
||||
JOIN atlas.platforms platform ON platform.id = source.platform_id
|
||||
WHERE platform.status = 'active' AND upper(platform.code) = 'OZON'`,
|
||||
);
|
||||
for (const source of sources.rows) {
|
||||
await this.schedulePlatform(source.platform_id);
|
||||
}
|
||||
}
|
||||
|
||||
private async schedulePlatform(platformId: string) {
|
||||
await this.database.transaction(async (tx) => {
|
||||
const source = await tx.query<{ revision: number }>(
|
||||
`SELECT revision FROM atlas.platform_catalog_sources
|
||||
WHERE platform_id = $1 FOR UPDATE`,
|
||||
[platformId],
|
||||
);
|
||||
if (!source.rows[0]) return;
|
||||
const pending = await tx.query<{ count: string }>(
|
||||
`SELECT count(*)::text AS count FROM atlas.platform_catalog_sync_runs
|
||||
WHERE platform_id = $1 AND status IN ('queued', 'running')`,
|
||||
[platformId],
|
||||
);
|
||||
if (Number(pending.rows[0]?.count ?? 0) >= 6) return;
|
||||
const candidates = await tx.query<Candidate>(
|
||||
`WITH possible AS (
|
||||
SELECT 'tree'::text AS scope, 'tree'::text AS scope_key,
|
||||
NULL::uuid AS category_id, NULL::uuid AS attribute_id,
|
||||
interval '24 hours' AS refresh_interval, 0 AS priority
|
||||
UNION ALL
|
||||
SELECT 'attributes', 'attributes:' || category.id, category.id, NULL::uuid,
|
||||
interval '24 hours', 1
|
||||
FROM atlas.platform_product_categories category
|
||||
WHERE category.platform_id = $1 AND category.is_active
|
||||
AND category.external_type_id IS NOT NULL AND category.external_type_id <> '0'
|
||||
UNION ALL
|
||||
SELECT 'dictionary', 'dictionary:' || attribute.id,
|
||||
attribute.platform_product_category_id, attribute.id,
|
||||
interval '7 days', 2
|
||||
FROM atlas.platform_product_category_attributes attribute
|
||||
JOIN atlas.platform_product_categories category
|
||||
ON category.id = attribute.platform_product_category_id
|
||||
WHERE attribute.platform_id = $1 AND attribute.is_active
|
||||
AND attribute.dictionary_id IS NOT NULL AND category.is_active
|
||||
)
|
||||
SELECT possible.scope, possible.scope_key, possible.category_id, possible.attribute_id
|
||||
FROM possible
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM atlas.platform_catalog_sync_runs run
|
||||
WHERE run.platform_id = $1 AND run.scope_key = possible.scope_key
|
||||
AND run.status = 'succeeded'
|
||||
AND run.completed_at > now() - possible.refresh_interval
|
||||
) AND NOT EXISTS (
|
||||
SELECT 1 FROM atlas.platform_catalog_sync_runs run
|
||||
WHERE run.platform_id = $1 AND run.scope_key = possible.scope_key
|
||||
AND run.created_at > now() - interval '1 hour'
|
||||
) AND NOT EXISTS (
|
||||
SELECT 1 FROM atlas.platform_catalog_sync_runs run
|
||||
WHERE run.platform_id = $1 AND run.scope_key = possible.scope_key
|
||||
AND run.status IN ('queued', 'running')
|
||||
)
|
||||
ORDER BY possible.priority, possible.scope_key LIMIT 6`,
|
||||
[platformId],
|
||||
);
|
||||
const capacity = 6 - Number(pending.rows[0]?.count ?? 0);
|
||||
for (const candidate of candidates.rows.slice(0, capacity)) {
|
||||
await enqueueScheduled(tx, platformId, source.rows[0].revision, candidate);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function enqueueScheduled(
|
||||
tx: DatabaseTransaction,
|
||||
platformId: string,
|
||||
sourceRevision: number,
|
||||
candidate: Candidate,
|
||||
) {
|
||||
const run = await tx.query<{ id: string }>(
|
||||
`INSERT INTO atlas.platform_catalog_sync_runs
|
||||
(platform_id, scope, scope_key, category_id, attribute_id,
|
||||
trigger_kind, source_revision)
|
||||
VALUES ($1, $2, $3, $4, $5, 'scheduled', $6)
|
||||
RETURNING id`,
|
||||
[platformId, candidate.scope, candidate.scope_key,
|
||||
candidate.category_id, candidate.attribute_id, sourceRevision],
|
||||
);
|
||||
await tx.query(
|
||||
`INSERT INTO atlas.platform_catalog_outbox_events (run_id, platform_id)
|
||||
VALUES ($1, $2)`,
|
||||
[run.rows[0].id, platformId],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user