|
| 1 | +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html |
| 2 | + |
| 3 | +exports[`generate-workers-entry-content > matches snapshot for multiple workers and redis url 1`] = ` |
| 4 | +" |
| 5 | +import { fileURLToPath } from 'node:url' |
| 6 | +import { resolve as resolvePath } from 'node:path' |
| 7 | +import { consola } from 'consola' |
| 8 | +import { $workers } from '#processor-utils' |
| 9 | +
|
| 10 | +// Initialize connection as early as possible so any imports that register |
| 11 | +// workers/queues have a valid connection available. |
| 12 | +const api = $workers() |
| 13 | +api.setConnection(new (await import("ioredis")).default("redis://localhost:6379")) |
| 14 | +
|
| 15 | +export async function createWorkersApp() { |
| 16 | +// Avoid EPIPE when stdout/stderr are closed by terminal (e.g., Ctrl+C piping) |
| 17 | +const handleStreamError = (err) => { |
| 18 | +try { |
| 19 | + const code = (typeof err === 'object' && err && 'code' in err) ? err.code : null |
| 20 | + if (code === 'EPIPE') return |
| 21 | +} catch (e) { console.warn?.('nuxt-processor: stream error inspection failed', e) } |
| 22 | +throw err |
| 23 | +} |
| 24 | +try { process.stdout?.on?.('error', handleStreamError) } catch (err) { console.warn('nuxt-processor: failed to attach stdout error handler', err) } |
| 25 | +try { process.stderr?.on?.('error', handleStreamError) } catch (err) { console.warn('nuxt-processor: failed to attach stderr error handler', err) } |
| 26 | +const modules = [ |
| 27 | +() => import("/app/server/workers/basic.ts"), |
| 28 | + () => import("/app/server/workers/hello.ts") |
| 29 | +] |
| 30 | +for (const loader of modules) { |
| 31 | +await loader() |
| 32 | +} |
| 33 | +// Parse --workers flag (e.g. --workers=basic,hello) |
| 34 | +const workersArg = process.argv.find(a => typeof a === 'string' && a.startsWith('--workers=')) |
| 35 | +const selectedWorkers = workersArg |
| 36 | + ? workersArg.split('=')[1].split(',').map(s => s.trim()).filter(Boolean) |
| 37 | + : null |
| 38 | +const workersToRun = selectedWorkers |
| 39 | + ? (Array.isArray(api.workers) ? api.workers.filter(w => w && selectedWorkers.includes(w.name)) : []) |
| 40 | + : (Array.isArray(api.workers) ? api.workers : []) |
| 41 | +const logger = consola.create({}).withTag('nuxt-processor') |
| 42 | +if (selectedWorkers && workersToRun.length === 0) { |
| 43 | + const available = (Array.isArray(api.workers) ? api.workers.map(w => w && w.name).filter(Boolean) : []) |
| 44 | + logger.warn('No workers matched --workers=' + selectedWorkers.join(',') + (available.length ? '. Available: ' + available.join(', ') : '.')) |
| 45 | + process.exit(1) |
| 46 | +} |
| 47 | +try { |
| 48 | +const workerNames = workersToRun.map(w => w && w.name).filter(Boolean) |
| 49 | +logger.info('starting workers:\\n' + workerNames.map(n => ' - ' + n).join('\\n')) |
| 50 | +for (const w of workersToRun) { |
| 51 | + w.on('error', (err) => logger.error('worker error', err)) |
| 52 | +} |
| 53 | +// Explicitly start workers since autorun is disabled |
| 54 | +for (const w of workersToRun) { |
| 55 | + try { |
| 56 | + // run() returns a promise that resolves when the worker stops; do not await to avoid blocking |
| 57 | + // eslint-disable-next-line promise/catch-or-return |
| 58 | + w.run().catch((err) => logger.error('worker run error', err)) |
| 59 | + } |
| 60 | + catch (err) { |
| 61 | + logger.error('failed to start worker', err) |
| 62 | + } |
| 63 | +} |
| 64 | +logger.success('workers started') |
| 65 | +} catch (err) { |
| 66 | +logger.error('failed to initialize workers', err) |
| 67 | +} |
| 68 | +const closeRunningWorkers = async () => { |
| 69 | + await Promise.allSettled(workersToRun.map(w => w.close())) |
| 70 | +} |
| 71 | +return { stop: closeRunningWorkers, workers: workersToRun } |
| 72 | +} |
| 73 | +
|
| 74 | +const isMain = (() => { |
| 75 | +try { |
| 76 | +if (typeof process === 'undefined' || !process.argv || !process.argv[1]) return false |
| 77 | +const argvPath = resolvePath(process.cwd?.() || '.', process.argv[1]) |
| 78 | +const filePath = fileURLToPath(import.meta.url) |
| 79 | +return filePath === argvPath |
| 80 | +} catch { |
| 81 | +return false |
| 82 | +} |
| 83 | +})() |
| 84 | +if (isMain) { |
| 85 | +const logger = consola.create({}).withTag('nuxt-processor') |
| 86 | +const appPromise = createWorkersApp().catch((err) => { |
| 87 | +logger.error('failed to start workers', err) |
| 88 | +process.exit(1) |
| 89 | +}) |
| 90 | +const shutdown = async () => { |
| 91 | +try { logger.info('closing workers...') } catch (err) { console.warn('nuxt-processor: failed to log shutdown start', err) } |
| 92 | +try { |
| 93 | + const app = await appPromise |
| 94 | + try { |
| 95 | + const names = (app?.workers || []).map(w => w && w.name).filter(Boolean) |
| 96 | + logger.info('closing workers:\\n' + names.map(n => ' - ' + n).join('\\n')) |
| 97 | + } catch (eL) { console.warn('nuxt-processor: failed to log workers list on shutdown', eL) } |
| 98 | + await app.stop() |
| 99 | + try { logger.success('workers closed') } catch (err2) { console.warn('nuxt-processor: failed to log shutdown complete', err2) } |
| 100 | +} |
| 101 | +finally { process.exit(0) } |
| 102 | +} |
| 103 | +;['SIGINT','SIGTERM','SIGQUIT'].forEach(sig => process.on(sig, shutdown)) |
| 104 | +process.on('beforeExit', shutdown) |
| 105 | +} |
| 106 | +
|
| 107 | +export default { createWorkersApp } |
| 108 | +" |
| 109 | +`; |
| 110 | +
|
| 111 | +exports[`generate-workers-entry-content > matches snapshot for single worker and undefined redis 1`] = ` |
| 112 | +" |
| 113 | +import { fileURLToPath } from 'node:url' |
| 114 | +import { resolve as resolvePath } from 'node:path' |
| 115 | +import { consola } from 'consola' |
| 116 | +import { $workers } from '#processor-utils' |
| 117 | +
|
| 118 | +// Initialize connection as early as possible so any imports that register |
| 119 | +// workers/queues have a valid connection available. |
| 120 | +const api = $workers() |
| 121 | +api.setConnection(undefined) |
| 122 | +
|
| 123 | +export async function createWorkersApp() { |
| 124 | +// Avoid EPIPE when stdout/stderr are closed by terminal (e.g., Ctrl+C piping) |
| 125 | +const handleStreamError = (err) => { |
| 126 | +try { |
| 127 | + const code = (typeof err === 'object' && err && 'code' in err) ? err.code : null |
| 128 | + if (code === 'EPIPE') return |
| 129 | +} catch (e) { console.warn?.('nuxt-processor: stream error inspection failed', e) } |
| 130 | +throw err |
| 131 | +} |
| 132 | +try { process.stdout?.on?.('error', handleStreamError) } catch (err) { console.warn('nuxt-processor: failed to attach stdout error handler', err) } |
| 133 | +try { process.stderr?.on?.('error', handleStreamError) } catch (err) { console.warn('nuxt-processor: failed to attach stderr error handler', err) } |
| 134 | +const modules = [ |
| 135 | +() => import("/path/to/worker.mjs") |
| 136 | +] |
| 137 | +for (const loader of modules) { |
| 138 | +await loader() |
| 139 | +} |
| 140 | +// Parse --workers flag (e.g. --workers=basic,hello) |
| 141 | +const workersArg = process.argv.find(a => typeof a === 'string' && a.startsWith('--workers=')) |
| 142 | +const selectedWorkers = workersArg |
| 143 | + ? workersArg.split('=')[1].split(',').map(s => s.trim()).filter(Boolean) |
| 144 | + : null |
| 145 | +const workersToRun = selectedWorkers |
| 146 | + ? (Array.isArray(api.workers) ? api.workers.filter(w => w && selectedWorkers.includes(w.name)) : []) |
| 147 | + : (Array.isArray(api.workers) ? api.workers : []) |
| 148 | +const logger = consola.create({}).withTag('nuxt-processor') |
| 149 | +if (selectedWorkers && workersToRun.length === 0) { |
| 150 | + const available = (Array.isArray(api.workers) ? api.workers.map(w => w && w.name).filter(Boolean) : []) |
| 151 | + logger.warn('No workers matched --workers=' + selectedWorkers.join(',') + (available.length ? '. Available: ' + available.join(', ') : '.')) |
| 152 | + process.exit(1) |
| 153 | +} |
| 154 | +try { |
| 155 | +const workerNames = workersToRun.map(w => w && w.name).filter(Boolean) |
| 156 | +logger.info('starting workers:\\n' + workerNames.map(n => ' - ' + n).join('\\n')) |
| 157 | +for (const w of workersToRun) { |
| 158 | + w.on('error', (err) => logger.error('worker error', err)) |
| 159 | +} |
| 160 | +// Explicitly start workers since autorun is disabled |
| 161 | +for (const w of workersToRun) { |
| 162 | + try { |
| 163 | + // run() returns a promise that resolves when the worker stops; do not await to avoid blocking |
| 164 | + // eslint-disable-next-line promise/catch-or-return |
| 165 | + w.run().catch((err) => logger.error('worker run error', err)) |
| 166 | + } |
| 167 | + catch (err) { |
| 168 | + logger.error('failed to start worker', err) |
| 169 | + } |
| 170 | +} |
| 171 | +logger.success('workers started') |
| 172 | +} catch (err) { |
| 173 | +logger.error('failed to initialize workers', err) |
| 174 | +} |
| 175 | +const closeRunningWorkers = async () => { |
| 176 | + await Promise.allSettled(workersToRun.map(w => w.close())) |
| 177 | +} |
| 178 | +return { stop: closeRunningWorkers, workers: workersToRun } |
| 179 | +} |
| 180 | +
|
| 181 | +const isMain = (() => { |
| 182 | +try { |
| 183 | +if (typeof process === 'undefined' || !process.argv || !process.argv[1]) return false |
| 184 | +const argvPath = resolvePath(process.cwd?.() || '.', process.argv[1]) |
| 185 | +const filePath = fileURLToPath(import.meta.url) |
| 186 | +return filePath === argvPath |
| 187 | +} catch { |
| 188 | +return false |
| 189 | +} |
| 190 | +})() |
| 191 | +if (isMain) { |
| 192 | +const logger = consola.create({}).withTag('nuxt-processor') |
| 193 | +const appPromise = createWorkersApp().catch((err) => { |
| 194 | +logger.error('failed to start workers', err) |
| 195 | +process.exit(1) |
| 196 | +}) |
| 197 | +const shutdown = async () => { |
| 198 | +try { logger.info('closing workers...') } catch (err) { console.warn('nuxt-processor: failed to log shutdown start', err) } |
| 199 | +try { |
| 200 | + const app = await appPromise |
| 201 | + try { |
| 202 | + const names = (app?.workers || []).map(w => w && w.name).filter(Boolean) |
| 203 | + logger.info('closing workers:\\n' + names.map(n => ' - ' + n).join('\\n')) |
| 204 | + } catch (eL) { console.warn('nuxt-processor: failed to log workers list on shutdown', eL) } |
| 205 | + await app.stop() |
| 206 | + try { logger.success('workers closed') } catch (err2) { console.warn('nuxt-processor: failed to log shutdown complete', err2) } |
| 207 | +} |
| 208 | +finally { process.exit(0) } |
| 209 | +} |
| 210 | +;['SIGINT','SIGTERM','SIGQUIT'].forEach(sig => process.on(sig, shutdown)) |
| 211 | +process.on('beforeExit', shutdown) |
| 212 | +} |
| 213 | +
|
| 214 | +export default { createWorkersApp } |
| 215 | +" |
| 216 | +`; |
0 commit comments