@igniter-js/jobs 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/AGENTS.md +117 -243
  2. package/README.md +311 -153
  3. package/dist/{adapter-CXZxomI9.d.mts → adapter-Cax_40HW.d.mts} +27 -6
  4. package/dist/{adapter-CXZxomI9.d.ts → adapter-Cax_40HW.d.ts} +27 -6
  5. package/dist/adapters/bun.d.mts +93 -0
  6. package/dist/adapters/bun.d.ts +93 -0
  7. package/dist/adapters/bun.js +914 -0
  8. package/dist/adapters/bun.js.map +1 -0
  9. package/dist/adapters/bun.mjs +912 -0
  10. package/dist/adapters/bun.mjs.map +1 -0
  11. package/dist/adapters/{memory.adapter.d.ts → mock.d.mts} +1 -3
  12. package/dist/adapters/{memory.adapter.d.mts → mock.d.ts} +1 -3
  13. package/dist/adapters/{memory.adapter.js → mock.js} +58 -25
  14. package/dist/adapters/mock.js.map +1 -0
  15. package/dist/adapters/{memory.adapter.mjs → mock.mjs} +58 -25
  16. package/dist/adapters/mock.mjs.map +1 -0
  17. package/dist/adapters/{bullmq.adapter.d.ts → node.d.mts} +1 -3
  18. package/dist/adapters/{bullmq.adapter.d.mts → node.d.ts} +1 -3
  19. package/dist/adapters/{bullmq.adapter.js → node.js} +117 -40
  20. package/dist/adapters/node.js.map +1 -0
  21. package/dist/adapters/{bullmq.adapter.mjs → node.mjs} +117 -40
  22. package/dist/adapters/node.mjs.map +1 -0
  23. package/dist/index.d.mts +17 -21
  24. package/dist/index.d.ts +17 -21
  25. package/dist/index.js +20 -1854
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +21 -1852
  28. package/dist/index.mjs.map +1 -1
  29. package/package.json +28 -40
  30. package/CHANGELOG.md +0 -13
  31. package/dist/adapters/bullmq.adapter.js.map +0 -1
  32. package/dist/adapters/bullmq.adapter.mjs.map +0 -1
  33. package/dist/adapters/index.d.mts +0 -143
  34. package/dist/adapters/index.d.ts +0 -143
  35. package/dist/adapters/index.js +0 -1891
  36. package/dist/adapters/index.js.map +0 -1
  37. package/dist/adapters/index.mjs +0 -1887
  38. package/dist/adapters/index.mjs.map +0 -1
  39. package/dist/adapters/memory.adapter.js.map +0 -1
  40. package/dist/adapters/memory.adapter.mjs.map +0 -1
package/AGENTS.md CHANGED
@@ -45,7 +45,7 @@ Maintainers must respect the following directory structure and responsibilities:
45
45
  - `queue.ts`: `IgniterQueue` facade for the queue builder.
46
46
  - **`src/adapters/`**: The infrastructure boundary.
47
47
  - `memory.adapter.ts`: Production-grade in-memory implementation for tests (non-persistent).
48
- - `sqlite.adapter.ts`: SQLite-based persistent adapter for local/desktop/CLI environments.
48
+ - `bun-sqlite.adapter.ts`: Bun-native SQLite adapter for local, desktop, CLI, and embedded workloads.
49
49
  - `bullmq.adapter.ts`: Reference to external `@igniter-js/adapter-bullmq` for production Redis-based queues.
50
50
  - **`src/errors/`**: Resiliency definitions.
51
51
  - `jobs.error.ts`: `IgniterJobsError`. Extends `IgniterError` with metadata-rich payloads and authoritative error codes.
@@ -157,7 +157,9 @@ Type Flow:
157
157
  The package provides organized subpath exports for optimized bundling:
158
158
 
159
159
  - **`@igniter-js/jobs`**: The main entry point. Use for `IgniterJobs` and `IgniterQueue`.
160
- - **`@igniter-js/jobs/adapters`**: Built-in adapters (Memory, SQLite, BullMQ wrapper).
160
+ - **`@igniter-js/jobs/adapters/node`**: Node.js adapters (`BullMQ` wrapper).
161
+ - **`@igniter-js/jobs/adapters/bun`**: Bun-native SQLite adapter.
162
+ - **`@igniter-js/jobs/adapters/mock`**: In-memory adapter for tests and local mocks.
161
163
  - **`@igniter-js/jobs/telemetry`**: Telemetry registry for registration.
162
164
 
163
165
  ### 9. Quick Start & Common Patterns
@@ -168,7 +170,7 @@ Setup your jobs in a central `src/services/jobs.ts` file:
168
170
 
169
171
  ```typescript
170
172
  import { IgniterJobs } from "@igniter-js/jobs";
171
- import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters";
173
+ import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters/node";
172
174
 
173
175
  export const jobs = IgniterJobs.create()
174
176
  .withAdapter(IgniterJobsBullMQAdapter.create({ redis }))
@@ -216,7 +218,7 @@ Prevent permanent failures in external API calls:
216
218
  #### Case 5: SaaS Multi-Tenant CSV Import
217
219
 
218
220
  - **Scenario:** Process 100k row CSV.
219
- - **Implementation:** `job.progress(percent)` every 100 rows for real-time progress bar.
221
+ - **Implementation:** `job.updateProgress?.(percent)` every 100 rows for real-time progress bar.
220
222
 
221
223
  ### 11. Domain-Specific Guidance
222
224
 
@@ -457,17 +459,17 @@ All adapters implement the `IgniterJobsAdapter` interface defined in `src/types/
457
459
 
458
460
  ### 17. Adapter Comparison Matrix
459
461
 
460
- | Feature | Memory | SQLite | BullMQ |
461
- |---------|--------|--------|--------|
462
- | **Persistence** | ❌ In-memory only | ✅ File-based | ✅ Redis |
463
- | **Multi-process** | ❌ Single process | ⚠️ Single process (WAL) | ✅ Distributed |
464
- | **Installation** | Built-in | `better-sqlite3` | `bullmq` + Redis |
465
- | **Use Case** | Tests, demos | Desktop, CLI, MCP | Production, scale |
466
- | **Job Limits** | Memory-bound | Disk-bound | Redis-bound |
467
- | **Worker Mechanism** | Immediate | Polling-based | Event-driven |
468
- | **Cron Jobs** | ⚠️ Basic | ⚠️ Basic | ✅ Full |
469
- | **Distributed Locking** | ❌ | ❌ | ✅ |
470
- | **Rate Limiting** | ⚠️ Basic | ⚠️ Basic | ✅ Advanced |
462
+ | Feature | Memory | Bun SQLite | BullMQ |
463
+ | ----------------------- | ----------------- | ------------------------ | ----------------- |
464
+ | **Persistence** | ❌ In-memory only | ✅ File-based | ✅ Redis |
465
+ | **Multi-process** | ❌ Single process | ⚠️ Single process/local | ✅ Distributed |
466
+ | **Installation** | Built-in | Bundled with package | `bullmq` + Redis |
467
+ | **Use Case** | Tests, demos | Desktop, CLI, local apps | Production, scale |
468
+ | **Job Limits** | Memory-bound | Disk-bound | Redis-bound |
469
+ | **Worker Mechanism** | Immediate | Embedded worker runtime | Event-driven |
470
+ | **Cron Jobs** | ⚠️ Basic | Supported | ✅ Supported |
471
+ | **Distributed Locking** | ❌ | ❌ | ✅ |
472
+ | **Rate Limiting** | ⚠️ Basic | Supported | ✅ Advanced |
471
473
 
472
474
  ---
473
475
 
@@ -490,7 +492,7 @@ No additional dependencies required. The adapter is built into `@igniter-js/jobs
490
492
 
491
493
  ```typescript
492
494
  import { IgniterJobs } from "@igniter-js/jobs";
493
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
495
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
494
496
 
495
497
  const adapter = IgniterJobsMemoryAdapter.create();
496
498
 
@@ -553,47 +555,36 @@ await worker.close();
553
555
 
554
556
  ---
555
557
 
556
- ### 19. SQLite Adapter (Desktop, CLI, MCP Servers)
558
+ ### 19. Bun SQLite Adapter (Desktop, CLI, Local Apps)
557
559
 
558
- The `IgniterJobsSQLiteAdapter` provides persistent job storage using SQLite, ideal for local environments where Redis is impractical.
560
+ The `IgniterJobsBunSQLiteAdapter` is the local persistent adapter for Bun runtimes. It is the recommended choice for desktop applications, embedded tools, local orchestrators, and Bun services that want SQLite-backed jobs without Redis.
559
561
 
560
562
  #### 19.1 When to Use
561
563
 
562
- - **Desktop Applications:** Tauri, Electron apps needing background tasks.
563
- - **CLI Tools:** Long-running commands with progress tracking.
564
- - **MCP Servers:** Model Context Protocol servers with job queues.
565
- - **Edge Deployments:** Single-node deployments.
566
- - **Local Development:** When you want jobs to survive restarts.
564
+ - **Desktop Applications:** Tauri or Electron apps with a Bun sidecar/runtime.
565
+ - **CLI Tools:** Long-running commands with progress tracking and durable jobs.
566
+ - **Local Services:** Single-node Bun services that need persistence and recurring jobs.
567
+ - **Embedded Workloads:** Sidecar workers, local automation, and job-heavy scripts.
567
568
 
568
569
  #### 19.2 Installation
569
570
 
570
- ```bash
571
- npm install better-sqlite3
572
- # or
573
- bun add better-sqlite3
574
- ```
575
-
576
- The `better-sqlite3` package is an optional peer dependency.
571
+ No extra adapter package is required. Install `@igniter-js/jobs`, run the app in Bun, and import the adapter from `@igniter-js/jobs/adapters/bun`.
577
572
 
578
573
  #### 19.3 Basic Usage
579
574
 
580
575
  ```typescript
581
576
  import { IgniterJobs } from "@igniter-js/jobs";
582
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
577
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
583
578
 
584
- // File-based (persistent)
585
- const adapter = IgniterJobsSQLiteAdapter.create({
579
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
586
580
  path: "./jobs.sqlite",
587
- });
588
-
589
- // In-memory (for tests)
590
- const memoryAdapter = IgniterJobsSQLiteAdapter.create({
591
- path: ":memory:",
581
+ durable: true,
592
582
  });
593
583
 
594
584
  const jobs = IgniterJobs.create()
595
585
  .withAdapter(adapter)
596
586
  .withService("desktop-app")
587
+ .withEnvironment("production")
597
588
  .withContext(async () => ({ settings: loadSettings() }))
598
589
  .addQueue(syncQueue)
599
590
  .build();
@@ -602,144 +593,52 @@ const jobs = IgniterJobs.create()
602
593
  #### 19.4 Configuration Options
603
594
 
604
595
  ```typescript
605
- interface IgniterJobsSQLiteAdapterOptions {
606
- /**
607
- * Path to the SQLite database file.
608
- * Use ":memory:" for in-memory database.
609
- * @example "./data/jobs.sqlite"
610
- */
596
+ interface IgniterJobsBunSQLiteAdapterOptions {
611
597
  path: string;
612
-
613
- /**
614
- * Polling interval in milliseconds for workers to check for new jobs.
615
- * Lower values = more responsive, higher CPU usage.
616
- * @default 500
617
- */
618
- pollingInterval?: number;
619
-
620
- /**
621
- * Enable WAL (Write-Ahead Logging) mode for better concurrent performance.
622
- * Recommended for production use.
623
- * @default true
624
- */
625
- enableWAL?: boolean;
598
+ durable?: boolean;
599
+ heartbeatInterval?: number;
600
+ pollTimeout?: number;
601
+ batchSize?: number;
602
+ lockDuration?: number;
603
+ maxStalledCount?: number;
626
604
  }
627
605
  ```
628
606
 
629
- #### 19.5 Database Schema
630
-
631
- The adapter automatically creates and manages the following tables:
632
-
633
- ```sql
634
- -- Main jobs table
635
- CREATE TABLE IF NOT EXISTS jobs (
636
- id TEXT PRIMARY KEY,
637
- queue TEXT NOT NULL,
638
- name TEXT NOT NULL,
639
- input TEXT, -- JSON serialized
640
- result TEXT, -- JSON serialized
641
- error TEXT,
642
- status TEXT NOT NULL DEFAULT 'waiting',
643
- progress INTEGER DEFAULT 0,
644
- priority INTEGER DEFAULT 0,
645
- attempts_made INTEGER DEFAULT 0,
646
- max_attempts INTEGER DEFAULT 1,
647
- delay_until INTEGER, -- Unix timestamp
648
- metadata TEXT, -- JSON serialized
649
- scope_type TEXT,
650
- scope_id TEXT,
651
- created_at INTEGER NOT NULL,
652
- started_at INTEGER,
653
- completed_at INTEGER
654
- );
655
-
656
- -- Indexes for efficient queries
657
- CREATE INDEX IF NOT EXISTS idx_jobs_queue_status ON jobs(queue, status);
658
- CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
659
- CREATE INDEX IF NOT EXISTS idx_jobs_priority ON jobs(priority DESC);
660
- CREATE INDEX IF NOT EXISTS idx_jobs_delay ON jobs(delay_until);
661
-
662
- -- Job logs table
663
- CREATE TABLE IF NOT EXISTS job_logs (
664
- id INTEGER PRIMARY KEY AUTOINCREMENT,
665
- job_id TEXT NOT NULL,
666
- level TEXT NOT NULL,
667
- message TEXT NOT NULL,
668
- timestamp INTEGER NOT NULL,
669
- FOREIGN KEY (job_id) REFERENCES jobs(id) ON DELETE CASCADE
670
- );
671
-
672
- -- Paused queues tracking
673
- CREATE TABLE IF NOT EXISTS paused_queues (
674
- name TEXT PRIMARY KEY,
675
- paused_at INTEGER NOT NULL
676
- );
677
- ```
607
+ #### 19.5 Runtime Characteristics
678
608
 
679
- #### 19.6 Worker Polling Mechanism
609
+ - Uses an embedded SQLite-backed runtime under Bun.
610
+ - Persists jobs to a local file path.
611
+ - Supports immediate dispatch, `at`, `delay`, `cron`, and `every` scheduling.
612
+ - Provides progress updates, logs, worker lifecycle events, and queue inspection APIs.
613
+ - Designed for local and embedded topologies, not distributed Redis-style clusters.
680
614
 
681
- Unlike event-driven adapters (BullMQ), the SQLite adapter uses a polling-based approach:
682
-
683
- ```
684
- ┌─────────────────────────────────────────────────────────────────┐
685
- │ Worker Polling Loop │
686
- ├─────────────────────────────────────────────────────────────────┤
687
- │ │
688
- │ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ │
689
- │ │ Wait │────▶│ Check Jobs │────▶│ Process Job │ │
690
- │ │ Polling │ │ Available? │ │ (if any) │ │
691
- │ │ Interval│ └─────────────┘ └─────────────┘ │
692
- │ └─────────┘ │ │ │
693
- │ ▲ │ No jobs │ Done │
694
- │ │ │ ▼ │
695
- │ └────────────────┴───────────────────┘ │
696
- │ │
697
- │ Query Priority: │
698
- │ 1. Delayed jobs ready to run (delay_until <= NOW) │
699
- │ 2. Waiting jobs, ordered by priority DESC │
700
- │ 3. Retry jobs (failed but attempts < max_attempts) │
701
- │ │
702
- └─────────────────────────────────────────────────────────────────┘
703
- ```
704
-
705
- #### 19.7 Complete Example
615
+ #### 19.6 Complete Example
706
616
 
707
617
  ```typescript
708
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
618
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
709
619
 
710
620
  async function main() {
711
- // 1. Create adapter
712
- const adapter = IgniterJobsSQLiteAdapter.create({
621
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
713
622
  path: "./my-app-jobs.sqlite",
714
- pollingInterval: 500,
715
- enableWAL: true,
623
+ durable: true,
624
+ batchSize: 25,
716
625
  });
717
626
 
718
- // 2. Register jobs
719
627
  adapter.registerJob("sync", "upload", {
720
- handler: async ({ input }) => {
628
+ handler: async ({ input, job }) => {
721
629
  const { fileId } = input as { fileId: string };
722
- // Simulate upload
630
+ await job.updateProgress?.(25, "Uploading metadata");
723
631
  await uploadFile(fileId);
632
+ await job.updateProgress?.(100, "Upload completed");
724
633
  return { uploaded: true };
725
634
  },
726
- onProgress: async ({ progress }) => {
727
- console.log(`Upload progress: ${progress}%`);
728
- },
729
635
  });
730
636
 
731
- // 3. Create worker
732
637
  const worker = await adapter.createWorker({
733
638
  queues: ["sync"],
734
639
  concurrency: 2,
735
- handlers: {
736
- onActive: ({ job }) => console.log(`Processing: ${job.id}`),
737
- onSuccess: ({ job }) => console.log(`Completed: ${job.id}`),
738
- onFailure: ({ job, error }) => console.error(`Failed: ${job.id}`, error),
739
- },
740
640
  });
741
641
 
742
- // 4. Dispatch jobs
743
642
  const jobId = await adapter.dispatch({
744
643
  queue: "sync",
745
644
  jobName: "upload",
@@ -747,50 +646,26 @@ async function main() {
747
646
  priority: 10,
748
647
  });
749
648
 
750
- console.log(`Dispatched job: ${jobId}`);
751
-
752
- // 5. Monitor status
753
- const counts = await adapter.getQueueJobCounts("sync");
754
- console.log(`Queue status:`, counts);
649
+ console.log(jobId);
755
650
 
756
- // 6. Graceful shutdown
757
651
  process.on("SIGINT", async () => {
758
652
  await worker.close();
759
653
  await adapter.shutdown();
760
- process.exit(0);
761
654
  });
762
655
  }
763
-
764
- main().catch(console.error);
765
656
  ```
766
657
 
767
- #### 19.8 Persistence & Recovery
658
+ #### 19.7 Persistence & Recovery
768
659
 
769
- Jobs are automatically persisted and survive process restarts:
660
+ - Jobs remain on disk across process restarts.
661
+ - Delayed and recurring work is persisted in the local SQLite backend.
662
+ - Worker shutdown should always call `adapter.shutdown()` during graceful exits.
770
663
 
771
- ```typescript
772
- // Session 1: Dispatch job and exit
773
- const adapter = IgniterJobsSQLiteAdapter.create({ path: "./jobs.sqlite" });
774
- await adapter.dispatch({
775
- queue: "emails",
776
- jobName: "send",
777
- input: { to: "user@example.com" },
778
- });
779
- await adapter.shutdown();
780
- // Process exits
781
-
782
- // Session 2: Jobs are still there
783
- const adapter2 = IgniterJobsSQLiteAdapter.create({ path: "./jobs.sqlite" });
784
- const jobs = await adapter2.searchJobs({ queue: "emails", status: ["waiting"] });
785
- console.log(jobs); // Shows the pending job from session 1
786
- ```
787
-
788
- #### 19.9 Limitations
664
+ #### 19.8 Limitations
789
665
 
790
- - **Single Process:** WAL mode helps, but true concurrent writes from multiple processes may cause issues.
791
- - **Polling Overhead:** Unlike event-driven systems, there's CPU overhead from polling.
792
- - **No Distributed Locking:** Cannot guarantee exactly-once processing across processes.
793
- - **Limited Cron:** Basic cron support without advanced scheduling features.
666
+ - **Local Topology:** The adapter is intended for Bun-local deployments and desktop-class runtimes.
667
+ - **No Redis-style Distribution:** Use BullMQ when you need multi-node horizontal workers.
668
+ - **Runtime Requirement:** This adapter runs only under Bun.
794
669
 
795
670
  ---
796
671
 
@@ -863,8 +738,9 @@ See `src/types/adapter.ts` for the complete interface definition.
863
738
  #### 21.2 Testing Custom Adapters
864
739
 
865
740
  Use the existing test suites as a reference:
741
+
866
742
  - `src/adapters/memory.adapter.spec.ts`
867
- - `src/adapters/sqlite.adapter.spec.ts`
743
+ - `src/core/telemetry.spec.ts`
868
744
 
869
745
  ---
870
746
 
@@ -877,18 +753,19 @@ The `examples/` directory contains runnable examples:
877
753
  ```
878
754
  packages/jobs/examples/
879
755
  ├── README.md # Example documentation
880
- └── sqlite-example.ts # Complete SQLite adapter demo
756
+ └── bun-sqlite-example.ts # Complete Bun SQLite adapter demo
881
757
  ```
882
758
 
883
- ### 23. Running the SQLite Example
759
+ ### 23. Running the Bun SQLite Example
884
760
 
885
761
  ```bash
886
762
  cd packages/jobs
887
- npx tsx examples/sqlite-example.ts
763
+ bun run examples/bun-sqlite-example.ts
888
764
  ```
889
765
 
890
766
  This example demonstrates:
891
- - Creating an SQLite adapter with file persistence
767
+
768
+ - Creating a Bun SQLite adapter with file persistence
892
769
  - Registering multiple job types
893
770
  - Priority-based job processing
894
771
  - Delayed job scheduling
@@ -900,32 +777,32 @@ This example demonstrates:
900
777
 
901
778
  ## VI. MIGRATION GUIDE
902
779
 
903
- ### 24. Migrating from Memory to SQLite
780
+ ### 24. Migrating from Memory to Bun SQLite
904
781
 
905
782
  For development to production-like local testing:
906
783
 
907
784
  ```typescript
908
785
  // Before: Memory adapter
909
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
786
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
910
787
  const adapter = IgniterJobsMemoryAdapter.create();
911
788
 
912
- // After: SQLite adapter
913
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
914
- const adapter = IgniterJobsSQLiteAdapter.create({
789
+ // After: Bun SQLite adapter
790
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
791
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
915
792
  path: "./dev-jobs.sqlite",
916
793
  });
917
794
 
918
795
  // Rest of the code remains identical!
919
796
  ```
920
797
 
921
- ### 25. Migrating from SQLite to BullMQ
798
+ ### 25. Migrating from Bun SQLite to BullMQ
922
799
 
923
800
  For local development to production:
924
801
 
925
802
  ```typescript
926
- // Before: SQLite adapter
927
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
928
- const adapter = IgniterJobsSQLiteAdapter.create({
803
+ // Before: Bun SQLite adapter
804
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
805
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
929
806
  path: "./jobs.sqlite",
930
807
  });
931
808
 
@@ -944,11 +821,9 @@ const adapter = IgniterJobsBullMQAdapter.create({
944
821
 
945
822
  ### Version 0.2.0 (2026-01-17)
946
823
 
947
- - **Added:** `IgniterJobsSQLiteAdapter` for persistent local job queues
948
- - **Added:** SQLite adapter comprehensive test suite (71 tests)
824
+ - **Added:** `IgniterJobsBunSQLiteAdapter` for persistent local Bun job queues
949
825
  - **Added:** `examples/` directory with runnable examples
950
- - **Added:** `better-sqlite3` as optional peer dependency
951
- - **Updated:** Adapter exports to include SQLite adapter
826
+ - **Updated:** Adapter exports to include Bun SQLite adapter
952
827
  - **Updated:** AGENTS.md with comprehensive adapter documentation
953
828
 
954
829
  ### Version 0.1.2 (2025-12-23)
@@ -965,16 +840,16 @@ const adapter = IgniterJobsBullMQAdapter.create({
965
840
 
966
841
  #### Q: Which adapter should I choose?
967
842
 
968
- | Environment | Recommended Adapter |
969
- |-------------|---------------------|
970
- | Unit/Integration Tests | Memory Adapter |
971
- | Desktop App (Tauri/Electron) | SQLite Adapter |
972
- | CLI Tool | SQLite Adapter |
973
- | MCP Server | SQLite Adapter |
974
- | Local Development | SQLite Adapter |
975
- | Production (Single Node) | SQLite or BullMQ |
976
- | Production (Multi Node) | BullMQ Adapter |
977
- | Serverless | BullMQ Adapter |
843
+ | Environment | Recommended Adapter |
844
+ | ---------------------------- | -------------------- |
845
+ | Unit/Integration Tests | Memory Adapter |
846
+ | Desktop App (Tauri/Electron) | Bun SQLite Adapter |
847
+ | CLI Tool | Bun SQLite Adapter |
848
+ | MCP Server | Bun SQLite Adapter |
849
+ | Local Development | Bun SQLite Adapter |
850
+ | Production (Single Node) | Bun SQLite or BullMQ |
851
+ | Production (Multi Node) | BullMQ Adapter |
852
+ | Serverless | BullMQ Adapter |
978
853
 
979
854
  #### Q: Can I switch adapters without changing business logic?
980
855
 
@@ -1003,14 +878,14 @@ adapter.registerJob("email", "send", {
1003
878
  adapter.registerJob("import", "csv", {
1004
879
  handler: async ({ input, job }) => {
1005
880
  const rows = await parseCSV(input.file);
1006
-
881
+
1007
882
  for (let i = 0; i < rows.length; i++) {
1008
883
  await processRow(rows[i]);
1009
-
884
+
1010
885
  // Update progress
1011
- await adapter.updateJobProgress(job.id, Math.floor((i / rows.length) * 100));
886
+ await job.updateProgress?.(Math.floor((i / rows.length) * 100));
1012
887
  }
1013
-
888
+
1014
889
  return { processed: rows.length };
1015
890
  },
1016
891
  onProgress: async ({ progress, message }) => {
@@ -1019,28 +894,24 @@ adapter.registerJob("import", "csv", {
1019
894
  });
1020
895
  ```
1021
896
 
1022
- #### Q: Can SQLite handle high throughput?
897
+ #### Q: Can Bun SQLite handle high throughput?
1023
898
 
1024
- SQLite with WAL mode can handle moderate throughput (100-1000 jobs/minute) on a single machine. For higher throughput or distributed processing, use BullMQ.
899
+ The Bun SQLite adapter handles local persistent workloads very well, especially for desktop, CLI, and embedded apps. For distributed workers or multi-node scale, use BullMQ.
1025
900
 
1026
901
  ### 27. Common Issues & Solutions
1027
902
 
1028
- #### Issue: "Cannot find module 'better-sqlite3'"
903
+ #### Issue: Bun SQLite adapter throws a runtime error in Node.js
1029
904
 
1030
- **Cause:** The `better-sqlite3` peer dependency is not installed.
905
+ **Cause:** The Bun SQLite adapter only runs inside Bun.
1031
906
 
1032
- **Solution:**
1033
- ```bash
1034
- npm install better-sqlite3
1035
- # If compilation fails on macOS:
1036
- npm install better-sqlite3 --build-from-source
1037
- ```
907
+ **Solution:** Use the BullMQ adapter in Node.js runtimes, or run the local adapter from Bun.
1038
908
 
1039
909
  #### Issue: Jobs stuck in "active" status after restart
1040
910
 
1041
911
  **Cause:** Process crashed while job was processing.
1042
912
 
1043
913
  **Solution:**
914
+
1044
915
  ```typescript
1045
916
  // On startup, reset stale active jobs
1046
917
  const staleJobs = await adapter.searchJobs({
@@ -1058,6 +929,7 @@ for (const job of staleJobs) {
1058
929
  **Cause:** Worker queues don't match job queue names.
1059
930
 
1060
931
  **Solution:**
932
+
1061
933
  ```typescript
1062
934
  // Ensure queue names match
1063
935
  adapter.registerJob("email", "send", { ... }); // Queue: "email"
@@ -1069,40 +941,43 @@ const worker = await adapter.createWorker({
1069
941
  });
1070
942
  ```
1071
943
 
1072
- #### Issue: SQLite database locked
944
+ #### Issue: Bun SQLite database locked
1073
945
 
1074
946
  **Cause:** Multiple processes trying to write simultaneously.
1075
947
 
1076
948
  **Solution:**
1077
- - Use WAL mode (enabled by default)
1078
- - Ensure only one process writes at a time
1079
- - Consider BullMQ for multi-process scenarios
949
+
950
+ - Ensure the local runtime is the primary writer to the database path.
951
+ - Avoid multiple unrelated Bun processes sharing the same local queue file.
952
+ - Consider BullMQ for multi-process or multi-node scenarios.
1080
953
 
1081
954
  ---
1082
955
 
1083
956
  ## IX. PERFORMANCE CONSIDERATIONS
1084
957
 
1085
- ### 28. SQLite Adapter Performance Tips
958
+ ### 28. Bun SQLite Adapter Performance Tips
1086
959
 
1087
- 1. **Use WAL Mode:** Always enable WAL mode for better read/write concurrency.
960
+ 1. **Use durable mode only for critical jobs:** durable writes trade throughput for stronger persistence.
1088
961
 
1089
- 2. **Tune Polling Interval:**
1090
- - Lower interval (100ms) = more responsive, higher CPU
1091
- - Higher interval (1000ms) = less responsive, lower CPU
962
+ 2. **Tune worker batch settings:** `batchSize`, `pollTimeout`, and `heartbeatInterval` affect local throughput.
1092
963
 
1093
964
  3. **Batch Operations:** When dispatching many jobs, consider batching:
965
+
1094
966
  ```typescript
1095
967
  const jobIds = [];
1096
968
  for (const item of items) {
1097
- jobIds.push(await adapter.dispatch({
1098
- queue: "process",
1099
- jobName: "item",
1100
- input: item,
1101
- }));
969
+ jobIds.push(
970
+ await adapter.dispatch({
971
+ queue: "process",
972
+ jobName: "item",
973
+ input: item,
974
+ }),
975
+ );
1102
976
  }
1103
977
  ```
1104
978
 
1105
979
  4. **Clean Old Jobs:** Periodically clean completed/failed jobs:
980
+
1106
981
  ```typescript
1107
982
  await adapter.cleanQueue("email", {
1108
983
  status: ["completed", "failed"],
@@ -1110,12 +985,12 @@ await adapter.cleanQueue("email", {
1110
985
  });
1111
986
  ```
1112
987
 
1113
- 5. **Index Usage:** The adapter creates optimized indexes for common queries.
988
+ 5. **Split high-volume workloads into dedicated queues:** local SQLite workloads benefit from clear queue boundaries.
1114
989
 
1115
990
  ### 29. Memory Considerations
1116
991
 
1117
992
  - **Memory Adapter:** All jobs stored in RAM; limit maxJobHistory.
1118
- - **SQLite Adapter:** Disk-based; memory usage scales with active jobs.
993
+ - **Bun SQLite Adapter:** Disk-based; memory usage scales with active workers and buffered operations.
1119
994
  - **BullMQ Adapter:** Redis memory; configure maxmemory policy.
1120
995
 
1121
996
  ---
@@ -1150,4 +1025,3 @@ const emailQueue = IgniterQueue.create("email")
1150
1025
  - **Encrypt at rest** if storing sensitive metadata.
1151
1026
 
1152
1027
  ---
1153
-