Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion scopes/scope/export/export.main.runtime.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import crypto from 'crypto';
import fs from 'fs-extra';
import type { CLIMain } from '@teambit/cli';
import { CLIAspect, MainRuntime } from '@teambit/cli';
Expand Down Expand Up @@ -678,7 +679,16 @@ if the scope name is wrong and you've already snapped/tagged, run "bit reset" to

async pushToRemotesCarefully(manyObjectsPerRemote: ObjectsPerRemote[], resumeExportId?: string) {
const remotes = manyObjectsPerRemote.map((o) => o.remote);
const clientId = resumeExportId || Date.now().toString();
// The clientId is both the pending-dir name AND the cross-client export lock: `export-validate`'s
// waitIfNeeded queue sorts pending-dir names and lets only the first proceed to validate+persist.
// A pure `Date.now()` is not collision-safe — two exports to the same remote within the same
// millisecond (e.g. concurrent CI runners pushing the same lane) get the same clientId, share one
// pending-dir, collapse the queue to a single entry, and both validate against the pre-persist
// state, silently losing one runner's update. A random suffix keeps the timestamp prefix (so the
// sorted queue still roughly preserves arrival order) while making a same-millisecond collision
// vanishingly unlikely (64 bits of randomness). Use node's built-in `crypto` rather than a
// component helper so this core aspect doesn't gain a new component dependency.
const clientId = resumeExportId || `${Date.now()}-${crypto.randomBytes(8).toString('hex')}`;
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
await this.pushRemotesPendingDir(clientId, manyObjectsPerRemote, resumeExportId);
await validateRemotes(remotes, clientId, Boolean(resumeExportId));
// Intentionally no cleanup on `persistRemotes` failure: pending dirs are the substrate for
Expand Down