mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add worker threads, persistent Python sidecar, graceful shutdown, and architectural improvements
- Graceful shutdown: SIGTERM/SIGINT handlers drain HTTP, stop workers, close DB - Thumbnail caching: disk-cached thumbnails with immutable Cache-Control headers - Worker thread pool: Piscina offloads Sharp processing off the main event loop - Persistent Python dispatcher: pre-imports ML libraries, eliminates cold-start latency - Tool page registry: declarative tool-to-component mapping replaces 750-line switch - File store cleanup: remove dead derived fields, stable files array reference - Job persistence: progress written to SQLite jobs table, stale jobs recovered on startup
This commit is contained in:
@@ -416,25 +416,31 @@ describe("FileStore", () => {
|
||||
expect(useFileStore.getState().processedSize).toBe(500);
|
||||
});
|
||||
|
||||
it("hasFiles returns true when entries exist", () => {
|
||||
expect(useFileStore.getState().hasFiles).toBe(false);
|
||||
it("entries.length reflects file count", () => {
|
||||
expect(useFileStore.getState().entries.length).toBe(0);
|
||||
useFileStore.getState().setFiles([makeFile("a.png")]);
|
||||
expect(useFileStore.getState().hasFiles).toBe(true);
|
||||
expect(useFileStore.getState().entries.length).toBe(1);
|
||||
});
|
||||
|
||||
it("allProcessed returns true when all entries are completed", () => {
|
||||
it("all entries completed can be derived from entries", () => {
|
||||
useFileStore.getState().setFiles([makeFile("a.png"), makeFile("b.png")]);
|
||||
expect(useFileStore.getState().allProcessed).toBe(false);
|
||||
const allDone = () =>
|
||||
useFileStore.getState().entries.length > 0 &&
|
||||
useFileStore.getState().entries.every((e) => e.status === "completed");
|
||||
expect(allDone()).toBe(false);
|
||||
|
||||
useFileStore.getState().updateEntry(0, { status: "completed" });
|
||||
expect(useFileStore.getState().allProcessed).toBe(false);
|
||||
expect(allDone()).toBe(false);
|
||||
|
||||
useFileStore.getState().updateEntry(1, { status: "completed" });
|
||||
expect(useFileStore.getState().allProcessed).toBe(true);
|
||||
expect(allDone()).toBe(true);
|
||||
});
|
||||
|
||||
it("allProcessed returns false when no entries", () => {
|
||||
expect(useFileStore.getState().allProcessed).toBe(false);
|
||||
it("empty entries means nothing is processed", () => {
|
||||
const allDone =
|
||||
useFileStore.getState().entries.length > 0 &&
|
||||
useFileStore.getState().entries.every((e) => e.status === "completed");
|
||||
expect(allDone).toBe(false);
|
||||
});
|
||||
|
||||
// -- setProcessedUrl (backward compat, updates current entry) -------------
|
||||
|
||||
Reference in New Issue
Block a user