Describe the issue
When Worker.start() is called on the non-legacy path, it makes two separate gRPC calls to fetch the engine version — one inside isLegacyEngine() and a second explicit call to fetchEngineVersion() immediately after. Both calls fetch identical data. The result from the first call is discarded, and the second call is used for eviction support checking and setting _internal.engineVersion.
Environment
- SDK: TypeScript (v1 worker,
client/worker/worker.ts)
- Engine: Cloud or Self-hosted (any version that supports
GetVersion)
Expected behavior
The engine version should be fetched once per Worker.start() invocation and the result reused across both the legacy engine check and eviction support check.
Code to Reproduce, Logs, or Screenshots
In client/worker/worker.ts:
async start() {
// Call 1: fetchEngineVersion is called internally inside isLegacyEngine
if (await isLegacyEngine(this._v1)) {
...
return this._legacyWorker.start();
}
// Call 2: fetchEngineVersion called again immediately after
const engineVersion = await fetchEngineVersion(this._v1).catch(() => undefined);
this._checkEvictionSupport(engineVersion);
this._internal.engineVersion = engineVersion;
return this._internal.start();
}
In client/worker/deprecated/legacy-worker.ts, isLegacyEngine internally calls fetchEngineVersion:
export async function isLegacyEngine(v1: HatchetClient): Promise<boolean> {
const version = await fetchEngineVersion(v1).catch(...);
if (!version || semverLessThan(version, MinEngineVersion.SLOT_CONFIG)) {
...
return true;
}
return false;
}
The fix is to fetch once in start(), inline the legacy check, and delete isLegacyEngine:
async start() {
const engineVersion = await fetchEngineVersion(this._v1).catch(() => undefined);
if (!engineVersion || semverLessThan(engineVersion, MinEngineVersion.SLOT_CONFIG)) {
const legacyConfig: CreateWorkerOpts = { ...this.config, ... };
this._legacyWorker = await LegacyDualWorker.create(this._v1, this.name, legacyConfig);
return this._legacyWorker.start();
}
this._checkEvictionSupport(engineVersion);
this._internal.engineVersion = engineVersion;
return this._internal.start();
}
Additional context
Three files need to change: client/worker/worker.ts (inline the fetch + legacy check), client/worker/deprecated/legacy-worker.ts and client/worker/deprecated/index.ts (delete isLegacyEngine as it becomes dead code). fetchEngineVersion itself remains unchanged.
🤖 AI Disclosure
Describe the issue
When
Worker.start()is called on the non-legacy path, it makes two separate gRPC calls to fetch the engine version — one insideisLegacyEngine()and a second explicit call tofetchEngineVersion()immediately after. Both calls fetch identical data. The result from the first call is discarded, and the second call is used for eviction support checking and setting_internal.engineVersion.Environment
client/worker/worker.ts)GetVersion)Expected behavior
The engine version should be fetched once per
Worker.start()invocation and the result reused across both the legacy engine check and eviction support check.Code to Reproduce, Logs, or Screenshots
In
client/worker/worker.ts:In
client/worker/deprecated/legacy-worker.ts,isLegacyEngineinternally callsfetchEngineVersion:The fix is to fetch once in
start(), inline the legacy check, and deleteisLegacyEngine:Additional context
Three files need to change:
client/worker/worker.ts(inline the fetch + legacy check),client/worker/deprecated/legacy-worker.tsandclient/worker/deprecated/index.ts(deleteisLegacyEngineas it becomes dead code).fetchEngineVersionitself remains unchanged.🤖 AI Disclosure
worker.tsanddeprecated/index.ts. Fix verified manually by tracing the call chain across both files.