fix: release codex lease on readonly prep failure
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -39,6 +39,7 @@ tmp/
|
|||||||
backups/
|
backups/
|
||||||
dist-backups/
|
dist-backups/
|
||||||
.deploy-backups/
|
.deploy-backups/
|
||||||
|
recovery/
|
||||||
cache/
|
cache/
|
||||||
runners/*/node_modules/
|
runners/*/node_modules/
|
||||||
runners/codex-runner-backups/
|
runners/codex-runner-backups/
|
||||||
|
|||||||
@@ -474,6 +474,55 @@ describe('agent-runner timeout behavior', () => {
|
|||||||
expect(spawnEnv?.CODEX_HOME).toBe('/tmp/host-reviewer-session/.codex');
|
expect(spawnEnv?.CODEX_HOME).toBe('/tmp/host-reviewer-session/.codex');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('releases the initial Codex auth lease when read-only session preparation fails', async () => {
|
||||||
|
vi.useRealTimers();
|
||||||
|
fakeProc = createFakeProcess();
|
||||||
|
|
||||||
|
const releaseLease = vi.fn();
|
||||||
|
const prepareGroupEnvironmentSpy = mockCodexLeaseEnvironment(releaseLease);
|
||||||
|
const readonlyError = new Error('Codex rotation pool unavailable');
|
||||||
|
const prepareReadonlySessionEnvironmentSpy = vi
|
||||||
|
.spyOn(agentRunnerEnvironment, 'prepareReadonlySessionEnvironment')
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw readonlyError;
|
||||||
|
});
|
||||||
|
const codexGroup: RegisteredGroup = {
|
||||||
|
...testGroup,
|
||||||
|
agentType: 'codex',
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(
|
||||||
|
runAgentProcess(
|
||||||
|
codexGroup,
|
||||||
|
{
|
||||||
|
...testInput,
|
||||||
|
roomRoleContext: {
|
||||||
|
serviceId: 'codex-review',
|
||||||
|
role: 'reviewer',
|
||||||
|
ownerServiceId: 'codex-main',
|
||||||
|
reviewerServiceId: 'codex-review',
|
||||||
|
failoverOwner: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
async () => {},
|
||||||
|
{
|
||||||
|
EJCLAW_UNSAFE_HOST_PAIRED_MODE: '1',
|
||||||
|
CLAUDE_CONFIG_DIR: '/tmp/host-reviewer-session',
|
||||||
|
EJCLAW_WORK_DIR: '/tmp/paired/task-1/reviewer',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).rejects.toThrow(readonlyError);
|
||||||
|
|
||||||
|
expect(prepareReadonlySessionEnvironmentSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(releaseLease).toHaveBeenCalledTimes(1);
|
||||||
|
} finally {
|
||||||
|
prepareReadonlySessionEnvironmentSpy.mockRestore();
|
||||||
|
prepareGroupEnvironmentSpy.mockRestore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('serializes roomRoleContext into the runner stdin payload', async () => {
|
it('serializes roomRoleContext into the runner stdin payload', async () => {
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
fakeProc = createFakeProcess();
|
fakeProc = createFakeProcess();
|
||||||
|
|||||||
@@ -157,21 +157,31 @@ export async function runAgentProcess(
|
|||||||
(input.roomRoleContext?.role === 'reviewer' ||
|
(input.roomRoleContext?.role === 'reviewer' ||
|
||||||
input.roomRoleContext?.role === 'arbiter')
|
input.roomRoleContext?.role === 'arbiter')
|
||||||
) {
|
) {
|
||||||
const readonlySession = prepareReadonlySessionEnvironment({
|
const isCodexGroup = (group.agentType || 'claude-code') === 'codex';
|
||||||
sessionDir: envOverrides.CLAUDE_CONFIG_DIR,
|
const previousCodexSessionAuth = codexSessionAuth;
|
||||||
chatJid: input.chatJid,
|
let readonlySession: ReturnType<typeof prepareReadonlySessionEnvironment>;
|
||||||
isMain: input.isMain,
|
try {
|
||||||
groupFolder: group.folder,
|
readonlySession = prepareReadonlySessionEnvironment({
|
||||||
agentType: group.agentType || 'claude-code',
|
sessionDir: envOverrides.CLAUDE_CONFIG_DIR,
|
||||||
memoryBriefing: input.memoryBriefing,
|
chatJid: input.chatJid,
|
||||||
role: input.roomRoleContext.role,
|
isMain: input.isMain,
|
||||||
ipcDir: env[EJCLAW_ENV.ipcDir],
|
groupFolder: group.folder,
|
||||||
hostIpcDir: env[EJCLAW_ENV.hostIpcDir],
|
agentType: group.agentType || 'claude-code',
|
||||||
workDir: envOverrides[EJCLAW_ENV.workDir] || env[EJCLAW_ENV.workDir],
|
memoryBriefing: input.memoryBriefing,
|
||||||
skillOverrides,
|
role: input.roomRoleContext.role,
|
||||||
});
|
ipcDir: env[EJCLAW_ENV.ipcDir],
|
||||||
if ((group.agentType || 'claude-code') === 'codex') {
|
hostIpcDir: env[EJCLAW_ENV.hostIpcDir],
|
||||||
releaseCodexAuthSession(codexSessionAuth);
|
workDir: envOverrides[EJCLAW_ENV.workDir] || env[EJCLAW_ENV.workDir],
|
||||||
|
skillOverrides,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (isCodexGroup) {
|
||||||
|
releaseCodexAuthSession(previousCodexSessionAuth);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
if (isCodexGroup) {
|
||||||
|
releaseCodexAuthSession(previousCodexSessionAuth);
|
||||||
codexSessionAuth = readonlySession.codexSessionAuth;
|
codexSessionAuth = readonlySession.codexSessionAuth;
|
||||||
env.CODEX_HOME = path.join(envOverrides.CLAUDE_CONFIG_DIR, '.codex');
|
env.CODEX_HOME = path.join(envOverrides.CLAUDE_CONFIG_DIR, '.codex');
|
||||||
if (readonlySession.codexHomeDir) {
|
if (readonlySession.codexHomeDir) {
|
||||||
|
|||||||
Reference in New Issue
Block a user