Skip to content

Commit 065aeb8

Browse files
committed
chore: wip
1 parent 5b41099 commit 065aeb8

25 files changed

+2802
-19
lines changed

build.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { dts } from 'bun-plugin-dtsx'
22

33
await Bun.build({
4-
entrypoints: ['src/index.ts'],
4+
entrypoints: ['packages/bun-queue/src/index.ts'],
55
outdir: './dist',
6-
plugins: [dts()],
6+
target: 'bun',
7+
plugins: [dts({
8+
root: 'packages/bun-queue/src'
9+
})],
710
})

examples/simple-laravel.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import {
2+
JobBase,
3+
dispatch,
4+
chain,
5+
type ShouldQueue,
6+
} from '../packages/bun-queue/src'
7+
8+
// Define a simple job class like Laravel
9+
class SendWelcomeEmailJob extends JobBase implements ShouldQueue {
10+
public queue = 'emails'
11+
public tries = 3
12+
public timeout = 30000
13+
14+
constructor(
15+
private userEmail: string,
16+
private userName: string
17+
) {
18+
super()
19+
}
20+
21+
async handle(): Promise<{ sent: boolean; messageId: string }> {
22+
console.log(`[SendWelcomeEmailJob] Sending welcome email to ${this.userEmail}`)
23+
console.log(`[SendWelcomeEmailJob] User: ${this.userName}`)
24+
25+
// Simulate email sending delay
26+
await new Promise(resolve => setTimeout(resolve, 1000))
27+
28+
// Simulate occasional failures
29+
if (Math.random() < 0.2) {
30+
throw new Error('Email service temporarily unavailable')
31+
}
32+
33+
const messageId = `msg_${Date.now()}_${Math.random().toString(36).substring(2)}`
34+
console.log(`[SendWelcomeEmailJob] ✅ Email sent successfully! Message ID: ${messageId}`)
35+
36+
return {
37+
sent: true,
38+
messageId,
39+
}
40+
}
41+
42+
uniqueId(): string {
43+
return `welcome_${this.userEmail}`
44+
}
45+
}
46+
47+
class ProcessUserAvatarJob extends JobBase implements ShouldQueue {
48+
public queue = 'images'
49+
public tries = 2
50+
51+
constructor(
52+
private userId: string,
53+
private imageUrl: string
54+
) {
55+
super()
56+
}
57+
58+
async handle(): Promise<{ processed: boolean; thumbnailUrl: string }> {
59+
console.log(`[ProcessUserAvatarJob] Processing avatar for user ${this.userId}`)
60+
console.log(`[ProcessUserAvatarJob] Image URL: ${this.imageUrl}`)
61+
62+
// Simulate image processing
63+
await new Promise(resolve => setTimeout(resolve, 1500))
64+
65+
const thumbnailUrl = `https://cdn.example.com/avatars/${this.userId}_thumb.jpg`
66+
console.log(`[ProcessUserAvatarJob] ✅ Avatar processed! Thumbnail: ${thumbnailUrl}`)
67+
68+
return {
69+
processed: true,
70+
thumbnailUrl,
71+
}
72+
}
73+
74+
uniqueId(): string {
75+
return `avatar_${this.userId}`
76+
}
77+
}
78+
79+
async function demonstrateLaravelAPI() {
80+
console.log('🚀 Laravel-like Queue API Demo\n')
81+
82+
// 1. Basic job dispatching (Laravel style)
83+
console.log('1. Basic job dispatching:')
84+
const emailJob = new SendWelcomeEmailJob('[email protected]', 'John Doe')
85+
const dispatchedEmailJob = await dispatch(emailJob)
86+
console.log(`✅ Email job dispatched with ID: ${dispatchedEmailJob.id}\n`)
87+
88+
// 2. Fluent job chaining (Laravel style)
89+
console.log('2. Fluent job chaining:')
90+
await chain(new SendWelcomeEmailJob('[email protected]', 'Jane Smith'))
91+
.onQueue('priority-emails')
92+
.withTries(5)
93+
.delay(2000) // 2 second delay
94+
.dispatch()
95+
console.log('✅ Priority email job queued with delay and custom tries\n')
96+
97+
// 3. Multiple jobs with different configurations
98+
console.log('3. Multiple jobs with different configurations:')
99+
100+
// Create jobs with method chaining
101+
const avatarJob = new ProcessUserAvatarJob('user123', 'https://example.com/avatar.jpg')
102+
.withTries(3)
103+
.withTimeout(60000)
104+
105+
const marketingEmail = new SendWelcomeEmailJob('[email protected]', 'Marketing Team')
106+
.onQueue('marketing-emails')
107+
.withTries(1)
108+
109+
// Dispatch them
110+
await Promise.all([
111+
dispatch(avatarJob),
112+
dispatch(marketingEmail),
113+
])
114+
115+
console.log('✅ Avatar processing and marketing email jobs dispatched\n')
116+
117+
// 4. Conditional dispatching
118+
console.log('4. Conditional dispatching:')
119+
const isNewUser = Math.random() > 0.5
120+
const welcomeJob = new SendWelcomeEmailJob('[email protected]', 'New User')
121+
122+
if (isNewUser) {
123+
await dispatch(welcomeJob)
124+
console.log('✅ Welcome email dispatched for new user')
125+
} else {
126+
console.log('ℹ️ User not new, skipping welcome email')
127+
}
128+
129+
console.log('\n🎉 Demo completed! Jobs are now being processed...')
130+
console.log('Note: In a real application, you would start workers to process these jobs.')
131+
}
132+
133+
// Simple worker simulation for demo purposes
134+
async function simulateWorkers() {
135+
console.log('\n👷 Starting simulated workers...\n')
136+
137+
// This is just for demo - in reality you'd use the actual queue processing
138+
const jobs = [
139+
new SendWelcomeEmailJob('[email protected]', 'Demo User'),
140+
new ProcessUserAvatarJob('demo123', 'https://example.com/demo.jpg'),
141+
]
142+
143+
for (const job of jobs) {
144+
try {
145+
console.log(`🔄 Processing ${job.constructor.name}...`)
146+
const result = await job.handle()
147+
console.log(`✅ Job completed:`, result)
148+
} catch (error) {
149+
console.log(`❌ Job failed:`, (error as Error).message)
150+
}
151+
console.log('') // Empty line for readability
152+
}
153+
}
154+
155+
async function main() {
156+
await demonstrateLaravelAPI()
157+
await simulateWorkers()
158+
}
159+
160+
main().catch((error) => {
161+
console.error('❌ Demo failed:', error)
162+
process.exit(1)
163+
})
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import { ScriptLoader } from './script-loader'
1+
import type { Command, ScriptMetadata } from './script-loader'
2+
import { ScriptLoader, ScriptLoaderError } from './script-loader'
23

3-
export { Command, ScriptLoaderError, ScriptMetadata } from './script-loader'
4+
export { ScriptLoader }
5+
export type { Command, ScriptMetadata }
6+
export { ScriptLoaderError }
47

58
const scriptLoader = new ScriptLoader()
69

7-
export { ScriptLoader, scriptLoader }
10+
export { scriptLoader }

packages/bun-queue/src/commands/script-loader.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -531,17 +531,20 @@ function splitFilename(filePath: string): {
531531
}
532532

533533
// Determine the project root
534-
// https://stackoverflow.com/a/18721515
535534
function getPkgJsonDir(): string {
536-
for (const modPath of module.paths || []) {
535+
// Use Bun-compatible approach to find project root
536+
let currentDir = process.cwd()
537+
while (currentDir !== path.dirname(currentDir)) {
537538
try {
538-
const prospectivePkgJsonDir = path.dirname(modPath)
539-
fs.accessSync(modPath, fs.constants.F_OK)
540-
return prospectivePkgJsonDir
539+
const pkgJsonPath = path.join(currentDir, 'package.json')
540+
fs.accessSync(pkgJsonPath, fs.constants.F_OK)
541+
return currentDir
542+
}
543+
catch (e) {
544+
currentDir = path.dirname(currentDir)
541545
}
542-
catch (e) {}
543546
}
544-
return ''
547+
return process.cwd()
545548
}
546549

547550
// https://stackoverflow.com/a/66842927

packages/bun-queue/src/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { QueueConfig } from './types'
2+
import process from 'node:process'
23
import { loadConfig } from 'bunfig'
34

4-
export const defaultConfig: QueueConfig = {
5+
const defaultConfig: QueueConfig = {
56
verbose: true,
67
logLevel: 'info',
78
prefix: 'queue',
@@ -23,6 +24,7 @@ export const defaultConfig: QueueConfig = {
2324
maxStalledJobRetries: 3,
2425
}
2526

27+
// Load unified config using bunfig
2628
// eslint-disable-next-line antfu/no-top-level-await
2729
export const config: QueueConfig = await loadConfig({
2830
name: 'queue',

0 commit comments

Comments
 (0)