Skip to content

Commit

Permalink
fix: wait egg background task done before destroy tegg ctx (#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
killagu authored Jan 29, 2023
1 parent 6b31708 commit deea4d8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
27 changes: 26 additions & 1 deletion plugin/tegg/app.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import './lib/AppLoadUnit';
import './lib/AppLoadUnitInstance';
import './lib/EggCompatibleObject';
import { Application } from 'egg';
import { Application, Context } from 'egg';
import { BackgroundTaskHelper, PrototypeUtil } from '@eggjs/tegg';
import { EggPrototype } from '@eggjs/tegg-metadata';
import { EggContextCompatibleHook } from './lib/EggContextCompatibleHook';
import { CompatibleUtil } from './lib/CompatibleUtil';
import { ModuleHandler } from './lib/ModuleHandler';
Expand All @@ -28,6 +30,29 @@ export default class App {
}

async didLoad() {
const eggRunInBackground = this.app.context.runInBackground;
this.app.context.runInBackground = function runInBackground(this: Context, scope: (ctx: Context) => Promise<any>) {
let resolveBackgroundTask;
const backgroundTaskPromise = new Promise(resolve => {
resolveBackgroundTask = resolve;
});
const newScope = async () => {
try {
await scope(this);
} finally {
resolveBackgroundTask();
}
};
Reflect.apply(eggRunInBackground, this, [ newScope ]);

const proto = PrototypeUtil.getClazzProto(BackgroundTaskHelper);
const eggObject = this.app.eggContainerFactory.getEggObject(proto as EggPrototype);
const backgroundTaskHelper = eggObject.obj as BackgroundTaskHelper;
backgroundTaskHelper.run(async () => {
await backgroundTaskPromise;
});
};

await this.app.moduleHandler.ready();
this.compatibleHook = new EggContextCompatibleHook(this.app.moduleHandler);
this.app.eggContextLifecycleUtil.registerLifecycle(this.compatibleHook);
Expand Down
9 changes: 8 additions & 1 deletion plugin/tegg/lib/EggContextCompatibleHook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LifecycleHook, ObjectInitType } from '@eggjs/tegg';
import { BackgroundTaskHelper, LifecycleHook, ObjectInitType, PrototypeUtil } from '@eggjs/tegg';
import { EggContainerFactory, EggContext, EggContextLifecycleContext } from '@eggjs/tegg-runtime';
import { EggPrototype } from '@eggjs/tegg-metadata';
import { ModuleHandler } from './ModuleHandler';
Expand Down Expand Up @@ -38,6 +38,13 @@ export class EggContextCompatibleHook implements LifecycleHook<EggContextLifecyc
await Promise.all(this.initProtoList.map(async proto => {
await EggContainerFactory.getOrCreateEggObject(proto);
}));
} else {
// Use for ctx.runInBackground.
// BackgroundTaskHelper should get by sync,
// or tegg context may be destroyed before background task run.
// So create it in preCreate.
const protoObj = PrototypeUtil.getClazzProto(BackgroundTaskHelper);
await EggContainerFactory.getOrCreateEggObject(protoObj as EggPrototype);
}
}
}
14 changes: 14 additions & 0 deletions plugin/tegg/test/app/extend/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import assert from 'assert';
import path from 'path';
import mm from 'egg-mock';
import { Application } from 'egg';
import sleep from 'mz-modules/sleep';
import AppService from '../../fixtures/apps/egg-app/modules/multi-module-service/AppService';
import PersistenceService from '../../fixtures/apps/egg-app/modules/multi-module-repo/PersistenceService';

Expand Down Expand Up @@ -50,4 +51,17 @@ describe('test/app/extend/context.test.ts', () => {
});
});
});

describe('runInBackground', () => {
it('should notify background task helper', async () => {
let backgroundIsDone = false;
await app.mockModuleContextScope(async ctx => {
ctx.runInBackground(async () => {
await sleep(100);
backgroundIsDone = true;
});
});
assert(backgroundIsDone);
});
});
});

0 comments on commit deea4d8

Please sign in to comment.