fix(gateway): should not refresh when application start from error recover (#2711)

* fix(gateway): should not refresh when application start from error recover

* chore: recover option
This commit is contained in:
ChengLei Shao 2023-09-25 15:26:52 +08:00 committed by GitHub
parent 89635982b4
commit 376a91b8ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 10 deletions

View File

@ -156,8 +156,12 @@ describe('gateway', () => {
return JSON.parse(messages[messages.length - 1]);
};
beforeEach(async () => {
const clearMessages = () => {
messages = [];
};
beforeEach(async () => {
clearMessages();
port = await startServerWithRandomPort(gateway.startHttpServer.bind(gateway));
});
@ -173,6 +177,55 @@ describe('gateway', () => {
await waitSecond();
});
describe('plugin manager api', () => {
let app;
beforeEach(async () => {
await connectClient(port);
app = new Application({
database: {
dialect: 'sqlite',
storage: ':memory:',
},
plugins: ['nocobase'],
});
await waitSecond();
await app.runAsCLI(['install'], { from: 'user' });
await app.runAsCLI(['start'], { from: 'user' });
await waitSecond();
clearMessages();
});
it('should silently handle the exception when the plugin does not exist', async () => {
await app.runAsCLI(['pm', 'add', 'not-exists-plugin'], { from: 'user' });
await waitSecond();
});
it('should display a notification-type error message when plugin installation fails', async () => {
const pluginClass = app.pm.get('mobile-client');
pluginClass.install = async () => {
throw new Error('install error');
};
await app.runAsCLI(['pm', 'enable', 'mobile-client'], { from: 'user' });
await waitSecond();
const runningMessage = messages
.map((m) => {
return JSON.parse(m);
})
.find((m) => {
return m.payload.code == 'APP_RUNNING';
});
expect(runningMessage.payload.refresh).not.toBeTruthy();
});
});
it('should receive app error message', async () => {
await connectClient(port);

View File

@ -260,12 +260,14 @@ export class AppSupervisor extends EventEmitter implements AsyncEmitter {
});
app.on('__started', async (_app, options) => {
const { maintainingStatus } = options;
const { maintainingStatus, options: startOptions } = options;
if (
maintainingStatus &&
['install', 'upgrade', 'pm.add', 'pm.update', 'pm.enable', 'pm.disable', 'pm.remove'].includes(
maintainingStatus.command.name,
)
) &&
!startOptions.recover
) {
this.setAppStatus(app.name, 'running', {
refresh: true,

View File

@ -88,6 +88,7 @@ interface StartOptions {
cliArgs?: any[];
dbSync?: boolean;
checkInstall?: boolean;
recover?: boolean;
}
type MaintainingStatus = 'command_begin' | 'command_end' | 'command_running' | 'command_error';
@ -471,14 +472,15 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
this.setMaintainingMessage('emit afterStart');
await this.emitAsync('afterStart', this, options);
await this.emitStartedEvent();
await this.emitStartedEvent(options);
this.stopped = false;
}
async emitStartedEvent() {
async emitStartedEvent(options: StartOptions = {}) {
await this.emitAsync('__started', this, {
maintainingStatus: lodash.cloneDeep(this._maintainingCommandStatus),
options,
});
}
@ -486,11 +488,11 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
return this._started;
}
async tryReloadOrRestart() {
async tryReloadOrRestart(options: StartOptions = {}) {
if (this._started) {
await this.restart();
await this.restart(options);
} else {
await this.reload();
await this.reload(options);
}
}

View File

@ -415,7 +415,9 @@ export class PluginManager {
installed: false,
},
});
await this.app.tryReloadOrRestart();
await this.app.tryReloadOrRestart({
recover: true,
});
throw error;
}
}
@ -467,7 +469,9 @@ export class PluginManager {
enabled: true,
},
});
await this.app.tryReloadOrRestart();
await this.app.tryReloadOrRestart({
recover: true,
});
throw error;
}
}