feat(TRUEREF-0009): implement indexing pipeline and job queue
Implements the end-to-end indexing pipeline with a SQLite-backed job queue, startup recovery, and REST API endpoints for job status. - IndexingPipeline: orchestrates crawl → parse → atomic replace → embed → repo stats update with progress tracking at each stage - JobQueue: sequential SQLite-backed queue (no external broker), deduplicates active jobs per repository, drains queued jobs on startup - startup.ts: stale job recovery (running→failed), repo state reset, singleton initialization wired from hooks.server.ts - GET /api/v1/jobs with repositoryId/status/limit filtering - GET /api/v1/jobs/[id] single job lookup - hooks.server.ts: initializes DB and pipeline on server start - 18 unit tests covering queue, pipeline stages, recovery, and atomicity Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
72
src/hooks.server.ts
Normal file
72
src/hooks.server.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* SvelteKit server hooks (TRUEREF-0009).
|
||||
*
|
||||
* Runs once when the Node.js server process starts. Initialises the database
|
||||
* and kicks off the indexing pipeline + job queue so queued jobs resume
|
||||
* automatically after a restart.
|
||||
*/
|
||||
|
||||
import { initializeDatabase } from '$lib/server/db/index.js';
|
||||
import { getClient } from '$lib/server/db/client.js';
|
||||
import { initializePipeline } from '$lib/server/pipeline/startup.js';
|
||||
import { EMBEDDING_CONFIG_KEY, createProviderFromConfig, defaultEmbeddingConfig } from '$lib/server/embeddings/factory.js';
|
||||
import { EmbeddingService } from '$lib/server/embeddings/embedding.service.js';
|
||||
import type { EmbeddingConfig } from '$lib/server/embeddings/factory.js';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Server initialisation — runs once on startup
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
try {
|
||||
initializeDatabase();
|
||||
|
||||
const db = getClient();
|
||||
|
||||
// Load persisted embedding configuration (if any).
|
||||
const configRow = db
|
||||
.prepare<[string], { value: string }>(`SELECT value FROM settings WHERE key = ?`)
|
||||
.get(EMBEDDING_CONFIG_KEY);
|
||||
|
||||
let embeddingService: EmbeddingService | null = null;
|
||||
|
||||
if (configRow) {
|
||||
try {
|
||||
const config: EmbeddingConfig =
|
||||
typeof configRow.value === 'string'
|
||||
? JSON.parse(configRow.value)
|
||||
: (configRow.value as EmbeddingConfig);
|
||||
|
||||
if (config.provider !== 'none') {
|
||||
const provider = createProviderFromConfig(config);
|
||||
embeddingService = new EmbeddingService(db, provider);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`[hooks.server] Could not load embedding config: ${err instanceof Error ? err.message : String(err)}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Use the default (noop) config so the pipeline is still wired up.
|
||||
const config = defaultEmbeddingConfig();
|
||||
if (config.provider !== 'none') {
|
||||
const provider = createProviderFromConfig(config);
|
||||
embeddingService = new EmbeddingService(db, provider);
|
||||
}
|
||||
}
|
||||
|
||||
initializePipeline(db, embeddingService);
|
||||
console.log('[hooks.server] Indexing pipeline initialised.');
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`[hooks.server] Failed to initialise server: ${err instanceof Error ? err.message : String(err)}`
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Request handler (pass-through)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
return resolve(event);
|
||||
};
|
||||
Reference in New Issue
Block a user