(ctx: Context)
| 140 | const id = process.env.exec_mode === 'cluster_mode' ? hostname() : nanoid(); |
| 141 | |
| 142 | export async function apply(ctx: Context) { |
| 143 | ctx.on('domain/delete', (domainId) => coll.deleteMany({ domainId })); |
| 144 | ctx.on('bus/broadcast', (event, payload, trace) => { |
| 145 | collEvent.insertOne({ |
| 146 | ack: [id], |
| 147 | event, |
| 148 | payload: BSON.EJSON.stringify(payload), |
| 149 | expire: new Date(Date.now() + 10000), |
| 150 | trace, |
| 151 | }); |
| 152 | }); |
| 153 | |
| 154 | if (process.env.NODE_APP_INSTANCE !== '0') return; |
| 155 | const stream = collEvent.watch(); |
| 156 | const handleEvent = async (doc: EventDoc) => { |
| 157 | process.send?.({ type: 'hydro:broadcast', data: doc }); |
| 158 | const payload = BSON.EJSON.parse(doc.payload); |
| 159 | await (bus.parallel as any)(doc.event, ...payload); |
| 160 | }; |
| 161 | stream.on('change', async (change) => { |
| 162 | if (change.operationType !== 'insert') return; |
| 163 | if (change.fullDocument.ack.includes(id)) return; |
| 164 | await handleEvent(change.fullDocument); |
| 165 | }); |
| 166 | stream.on('error', async () => { |
| 167 | // The $changeStream stage is only supported on replica sets |
| 168 | logger.info('No replica set found.'); |
| 169 | while (true) { |
| 170 | let res; |
| 171 | try { |
| 172 | // eslint-disable-next-line no-await-in-loop |
| 173 | res = await collEvent.findOneAndUpdate( |
| 174 | { expire: { $gt: new Date() }, ack: { $nin: [id] } }, |
| 175 | { $push: { ack: id } }, |
| 176 | ); |
| 177 | } catch (e) { |
| 178 | logger.error(e); |
| 179 | // eslint-disable-next-line no-await-in-loop |
| 180 | await sleep(50); // This allows exiting when shutting down |
| 181 | continue; |
| 182 | } |
| 183 | if (argv.options.showEvent) logger.info('Event: %o', res); |
| 184 | // eslint-disable-next-line no-await-in-loop |
| 185 | await (res ? handleEvent(res) : sleep(500)); |
| 186 | } |
| 187 | }); |
| 188 | await db.ensureIndexes(collEvent, { name: 'expire', key: { expire: 1 }, expireAfterSeconds: 0 }); |
| 189 | await db.ensureIndexes(coll, { name: 'task', key: { type: 1, subType: 1, priority: -1 } }); |
| 190 | } |
| 191 | |
| 192 | export default TaskModel; |
| 193 | global.Hydro.model.task = TaskModel; |
nothing calls this directly
no test coverage detected