Skip to content

Commit 71cec5a

Browse files
authored
Purge leftover information in my channel table when purging playbooks (#9057)
* Purge leftover information in my channel table when purging playbooks * Add comment * Clear the sync ephemeral store on plugin disable
1 parent d653d55 commit 71cec5a

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

app/products/playbooks/actions/local/version.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,29 @@
44
import {SYSTEM_IDENTIFIERS} from '@constants/database';
55
import DatabaseManager from '@database/manager';
66
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
7+
import {getMyChannel} from '@queries/servers/channel';
78
import {querySystemValue} from '@queries/servers/system';
9+
import TestHelper from '@test/test_helper';
810

11+
import {updateLastPlaybookRunsFetchAt} from './channel';
912
import {setPlaybooksVersion} from './version';
1013

1114
import type ServerDataOperator from '@database/operator/server_data_operator';
1215

1316
const serverUrl = 'baseHandler.test.com';
17+
const channelId = 'channelid';
1418
let operator: ServerDataOperator;
1519

20+
const channel: Channel = TestHelper.fakeChannel({
21+
id: channelId,
22+
team_id: 'teamid1',
23+
});
24+
25+
const channelMember: ChannelMembership = TestHelper.fakeChannelMember({
26+
id: 'id',
27+
channel_id: channelId,
28+
});
29+
1630
beforeEach(async () => {
1731
await DatabaseManager.init([serverUrl]);
1832
operator = DatabaseManager.serverDatabases[serverUrl]!.operator;
@@ -50,6 +64,11 @@ describe('setPlaybooksVersion', () => {
5064

5165
it('should purge playbooks when version is empty', async () => {
5266
const database = operator.database;
67+
68+
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
69+
await operator.handleMyChannel({channels: [channel], myChannels: [channelMember], prepareRecordsOnly: false});
70+
await updateLastPlaybookRunsFetchAt(serverUrl, channelId, 1234);
71+
5372
jest.spyOn(database.adapter, 'unsafeExecute').mockImplementation(() => {
5473
return Promise.resolve();
5574
});
@@ -65,10 +84,18 @@ describe('setPlaybooksVersion', () => {
6584
[`DELETE FROM ${PLAYBOOK_TABLES.PLAYBOOK_CHECKLIST_ITEM}`, []],
6685
],
6786
});
87+
88+
const myChannel = await getMyChannel(operator.database, channelId);
89+
expect(myChannel?.lastPlaybookRunsFetchAt).toBe(0);
6890
});
6991

7092
it('should not purge playbooks when version is not empty', async () => {
7193
const database = operator.database;
94+
95+
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
96+
await operator.handleMyChannel({channels: [channel], myChannels: [channelMember], prepareRecordsOnly: false});
97+
await updateLastPlaybookRunsFetchAt(serverUrl, channelId, 1234);
98+
7299
jest.spyOn(database.adapter, 'unsafeExecute').mockImplementation(() => {
73100
return Promise.resolve();
74101
});
@@ -78,6 +105,8 @@ describe('setPlaybooksVersion', () => {
78105
expect(data).toBe(true);
79106

80107
expect(database.adapter.unsafeExecute).not.toHaveBeenCalled();
108+
const myChannel = await getMyChannel(operator.database, channelId);
109+
expect(myChannel?.lastPlaybookRunsFetchAt).toBe(1234);
81110
});
82111

83112
it('should handle purge playbooks errors', async () => {

app/products/playbooks/actions/local/version.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
22
// See LICENSE.txt for license information.
33

4-
import {SYSTEM_IDENTIFIERS} from '@constants/database';
4+
import {Q} from '@nozbe/watermelondb';
5+
6+
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
57
import DatabaseManager from '@database/manager';
68
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
9+
import EphemeralStore from '@store/ephemeral_store';
10+
11+
import type {MyChannelModel} from '@database/models/server';
712

813
export const setPlaybooksVersion = async (serverUrl: string, version: string) => {
914
try {
@@ -21,6 +26,8 @@ export const setPlaybooksVersion = async (serverUrl: string, version: string) =>
2126
if (error) {
2227
return {error};
2328
}
29+
30+
EphemeralStore.clearChannelPlaybooksSynced(serverUrl);
2431
}
2532

2633
return {data: true};
@@ -32,14 +39,25 @@ export const setPlaybooksVersion = async (serverUrl: string, version: string) =>
3239
const purgePlaybooks = async (serverUrl: string) => {
3340
try {
3441
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
35-
await database.write(() => {
36-
return database.adapter.unsafeExecute({
42+
const models = await database.collections.get<MyChannelModel>(MM_TABLES.SERVER.MY_CHANNEL).query(Q.where('last_playbook_runs_fetch_at', Q.gt(0)));
43+
44+
await database.write(async () => {
45+
await database.adapter.unsafeExecute({
3746
sqls: [
3847
[`DELETE FROM ${PLAYBOOK_TABLES.PLAYBOOK_RUN}`, []],
3948
[`DELETE FROM ${PLAYBOOK_TABLES.PLAYBOOK_CHECKLIST}`, []],
4049
[`DELETE FROM ${PLAYBOOK_TABLES.PLAYBOOK_CHECKLIST_ITEM}`, []],
4150
],
4251
});
52+
53+
// Process each model sequentially to prevent overwhelming the event loop with excessive promises
54+
// and to avoid overloading the database with concurrent write operations, especially when handling a large number of channels.
55+
for await (const model of models) {
56+
await model.update((channel) => {
57+
channel.lastPlaybookRunsFetchAt = 0;
58+
return channel;
59+
});
60+
}
4361
});
4462
} catch (error) {
4563
return {error};

0 commit comments

Comments
 (0)