feat: not uygulaması ve altyapısını ekle
- iOS Memos benzeri PWA ön yüz eklendi (React, Tailwind) - Express tabanlı arka uç, AnythingLLM API entegrasyonu ve senkronizasyon kuyruğu oluşturuldu - Docker, TypeScript ve proje konfigürasyonları tanımlandı
This commit is contained in:
27
backend/src/queue/cleanup.worker.ts
Normal file
27
backend/src/queue/cleanup.worker.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { removeDocuments } from "../anythingllm/anythingllm.client.js";
|
||||
import type { CleanupJob } from "./queue.js";
|
||||
import { logError } from "../utils/logger.js";
|
||||
import { readIndex, writeIndex } from "../notes/notes.storage.js";
|
||||
|
||||
export async function handleCleanupJob(job: CleanupJob): Promise<void> {
|
||||
try {
|
||||
await removeDocuments([job.oldLocation]);
|
||||
const index = await readIndex();
|
||||
const updated = index.map((item) => {
|
||||
if (item.id === job.id) {
|
||||
return {
|
||||
...item,
|
||||
sync: {
|
||||
...item.sync,
|
||||
cleanupPending: false
|
||||
}
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
await writeIndex(updated);
|
||||
} catch (error) {
|
||||
logError("Temizlik kuyrugu hatasi", { error: (error as Error).message });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
86
backend/src/queue/queue.ts
Normal file
86
backend/src/queue/queue.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import path from "path";
|
||||
import { readJsonFile, writeJsonFile } from "../utils/fileUtils.js";
|
||||
import { config } from "../config.js";
|
||||
import { logError, logInfo } from "../utils/logger.js";
|
||||
|
||||
export type CleanupJob = {
|
||||
id: string;
|
||||
oldLocation: string;
|
||||
attempts: number;
|
||||
nextRunAt: string;
|
||||
};
|
||||
|
||||
const backoffSeconds = [5, 15, 30];
|
||||
|
||||
export class CleanupQueue {
|
||||
private jobs: CleanupJob[] = [];
|
||||
private running = false;
|
||||
private timer?: NodeJS.Timeout;
|
||||
private readonly filePath: string;
|
||||
private readonly handler: (job: CleanupJob) => Promise<void>;
|
||||
|
||||
constructor(handler: (job: CleanupJob) => Promise<void>) {
|
||||
this.handler = handler;
|
||||
this.filePath = path.join(config.NOTES_DIR, "cleanup-queue.json");
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
this.jobs = await readJsonFile<CleanupJob[]>(this.filePath, []);
|
||||
}
|
||||
|
||||
async persist(): Promise<void> {
|
||||
await writeJsonFile(this.filePath, this.jobs);
|
||||
}
|
||||
|
||||
async enqueue(job: CleanupJob): Promise<void> {
|
||||
this.jobs.push(job);
|
||||
await this.persist();
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.timer) {
|
||||
return;
|
||||
}
|
||||
this.timer = setInterval(() => void this.tick(), 1000);
|
||||
logInfo("Temizlik kuyrugu calisiyor");
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async tick(): Promise<void> {
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
const now = Date.now();
|
||||
const jobIndex = this.jobs.findIndex((job) => new Date(job.nextRunAt).getTime() <= now);
|
||||
if (jobIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const job = this.jobs[jobIndex];
|
||||
this.running = true;
|
||||
try {
|
||||
await this.handler(job);
|
||||
this.jobs.splice(jobIndex, 1);
|
||||
await this.persist();
|
||||
logInfo("Temizlik basarili", { jobId: job.id });
|
||||
} catch (error) {
|
||||
job.attempts += 1;
|
||||
if (job.attempts >= backoffSeconds.length) {
|
||||
logError("Temizlik en fazla deneme sayisina ulasti", { jobId: job.id });
|
||||
this.jobs.splice(jobIndex, 1);
|
||||
} else {
|
||||
const delay = backoffSeconds[job.attempts - 1] * 1000;
|
||||
job.nextRunAt = new Date(Date.now() + delay).toISOString();
|
||||
}
|
||||
await this.persist();
|
||||
} finally {
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user