fix(worker): Permission syncer fixes (#624)
Some checks failed
Publish to ghcr / build (linux/amd64, blacksmith-4vcpu-ubuntu-2404) (push) Has been cancelled
Publish to ghcr / build (linux/arm64, blacksmith-8vcpu-ubuntu-2204-arm) (push) Has been cancelled
Update Roadmap Released / update (push) Has been cancelled
Publish to ghcr / merge (push) Has been cancelled

This commit is contained in:
Brendan Kellam 2025-11-19 22:14:23 -08:00 committed by GitHub
parent 97dd54d48f
commit 09507d3e89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 19 additions and 8 deletions

View file

@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed spurious infinite loads with explore panel, file tree, and file search command. [#617](https://github.com/sourcebot-dev/sourcebot/pull/617) - Fixed spurious infinite loads with explore panel, file tree, and file search command. [#617](https://github.com/sourcebot-dev/sourcebot/pull/617)
- Wipe search context on init if entitlement no longer exists [#618](https://github.com/sourcebot-dev/sourcebot/pull/618) - Wipe search context on init if entitlement no longer exists [#618](https://github.com/sourcebot-dev/sourcebot/pull/618)
- Fixed Bitbucket repository exclusions not supporting glob patterns. [#620](https://github.com/sourcebot-dev/sourcebot/pull/620) - Fixed Bitbucket repository exclusions not supporting glob patterns. [#620](https://github.com/sourcebot-dev/sourcebot/pull/620)
- Fixed issue where the repo driven permission syncer was attempting to sync public repositories. [#624](https://github.com/sourcebot-dev/sourcebot/pull/624)
- Fixed issue where worker would not shutdown while a permission sync job (repo or user) was in progress. [#624](https://github.com/sourcebot-dev/sourcebot/pull/624)
## [4.9.2] - 2025-11-13 ## [4.9.2] - 2025-11-13

View file

@ -102,7 +102,7 @@ export class AccountPermissionSyncer {
if (this.interval) { if (this.interval) {
clearInterval(this.interval); clearInterval(this.interval);
} }
await this.worker.close(); await this.worker.close(/* force = */ true);
await this.queue.close(); await this.queue.close();
} }

View file

@ -55,19 +55,27 @@ export class RepoPermissionSyncer {
const repos = await this.db.repo.findMany({ const repos = await this.db.repo.findMany({
// Repos need their permissions to be synced against the code host when... // Repos need their permissions to be synced against the code host when...
where: { where: {
// They belong to a code host that supports permissions syncing
AND: [ AND: [
// They are not public. Public repositories are always visible to all users, therefore we don't
// need to explicitly perform permission syncing for them.
// @see: packages/web/src/prisma.ts
{
isPublic: false
},
// They belong to a code host that supports permissions syncing
{ {
external_codeHostType: { external_codeHostType: {
in: PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES, in: PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES,
} }
}, },
// They have not been synced within the threshold date.
{ {
OR: [ OR: [
{ permissionSyncedAt: null }, { permissionSyncedAt: null },
{ permissionSyncedAt: { lt: thresholdDate } }, { permissionSyncedAt: { lt: thresholdDate } },
], ],
}, },
// There aren't any active or recently failed jobs.
{ {
NOT: { NOT: {
permissionSyncJobs: { permissionSyncJobs: {
@ -106,7 +114,7 @@ export class RepoPermissionSyncer {
if (this.interval) { if (this.interval) {
clearInterval(this.interval); clearInterval(this.interval);
} }
await this.worker.close(); await this.worker.close(/* force = */ true);
await this.queue.close(); await this.queue.close();
} }

View file

@ -112,19 +112,20 @@ const listenToShutdownSignals = () => {
await api.dispose(); await api.dispose();
await shutdownPosthog(); await shutdownPosthog();
logger.info('All workers shut down gracefully'); logger.info('All workers shut down gracefully');
signals.forEach(sig => process.removeListener(sig, cleanup)); signals.forEach(sig => process.removeListener(sig, cleanup));
return 0;
} catch (error) { } catch (error) {
Sentry.captureException(error); Sentry.captureException(error);
logger.error('Error shutting down worker:', error); logger.error('Error shutting down worker:', error);
return 1;
} }
} }
signals.forEach(signal => { signals.forEach(signal => {
process.on(signal, (err) => { process.on(signal, (err) => {
cleanup(err).finally(() => { cleanup(err).then(code => {
process.kill(process.pid, signal); process.exit(code);
}); });
}); });
}); });
@ -132,14 +133,14 @@ const listenToShutdownSignals = () => {
// Register handlers for uncaught exceptions and unhandled rejections // Register handlers for uncaught exceptions and unhandled rejections
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
logger.error(`Uncaught exception: ${err.message}`); logger.error(`Uncaught exception: ${err.message}`);
cleanup('uncaughtException').finally(() => { cleanup('uncaughtException').then(() => {
process.exit(1); process.exit(1);
}); });
}); });
process.on('unhandledRejection', (reason, promise) => { process.on('unhandledRejection', (reason, promise) => {
logger.error(`Unhandled rejection at: ${promise}, reason: ${reason}`); logger.error(`Unhandled rejection at: ${promise}, reason: ${reason}`);
cleanup('unhandledRejection').finally(() => { cleanup('unhandledRejection').then(() => {
process.exit(1); process.exit(1);
}); });
}); });