feat: 명령어 요청 ID 처리 개선 및 상태 응답 기능 업데이트
This commit is contained in:
@@ -27,7 +27,10 @@ export class InMemoryTurnDaemonTransport implements TurnDaemonTransport {
|
||||
|
||||
// 테스트용: 메모리 큐에 명령을 저장하고 requestId를 반환한다.
|
||||
async sendCommand(command: TurnDaemonCommand): Promise<string> {
|
||||
const requestId = command.type === 'getStatus' ? command.requestId : randomUUID();
|
||||
const requestId =
|
||||
command.type === 'getStatus' && command.requestId
|
||||
? command.requestId
|
||||
: randomUUID();
|
||||
this.commands.push({
|
||||
requestId,
|
||||
sentAt: new Date().toISOString(),
|
||||
|
||||
@@ -29,7 +29,10 @@ type RedisStreamReadResponse = Array<{
|
||||
}>;
|
||||
|
||||
const buildCommandEnvelope = (command: TurnDaemonCommand): TurnDaemonCommandEnvelope => {
|
||||
const requestId = command.type === 'getStatus' ? command.requestId : randomUUID();
|
||||
const requestId =
|
||||
command.type === 'getStatus' && command.requestId
|
||||
? command.requestId
|
||||
: randomUUID();
|
||||
return {
|
||||
requestId,
|
||||
sentAt: new Date().toISOString(),
|
||||
|
||||
@@ -1,89 +1,16 @@
|
||||
export type TurnDaemonState = 'idle' | 'running' | 'flushing' | 'paused' | 'stopping';
|
||||
import type { TurnDaemonCommand, TurnDaemonEvent } from '@sammo-ts/common';
|
||||
|
||||
export type RunReason = 'schedule' | 'manual' | 'poke';
|
||||
|
||||
export interface TurnRunBudget {
|
||||
budgetMs: number;
|
||||
maxGenerals: number;
|
||||
catchUpCap: number;
|
||||
}
|
||||
|
||||
export interface TurnCheckpoint {
|
||||
turnTime: string;
|
||||
generalId?: number;
|
||||
year: number;
|
||||
month: number;
|
||||
}
|
||||
|
||||
export interface TurnRunResult {
|
||||
lastTurnTime: string;
|
||||
processedGenerals: number;
|
||||
processedTurns: number;
|
||||
durationMs: number;
|
||||
partial: boolean;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export interface TurnDaemonStatus {
|
||||
state: TurnDaemonState;
|
||||
running: boolean;
|
||||
paused: boolean;
|
||||
lastError?: string;
|
||||
lastRunAt?: string;
|
||||
lastDurationMs?: number;
|
||||
lastTurnTime?: string;
|
||||
nextTurnTime?: string;
|
||||
pendingReason?: RunReason;
|
||||
queueDepth: number;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export type TurnDaemonMutationCommand =
|
||||
| { type: 'troopJoin'; generalId: number; troopId: number }
|
||||
| { type: 'troopExit'; generalId: number };
|
||||
|
||||
// 턴 데몬 제어 요청은 Redis 스트림으로 전달한다.
|
||||
export type TurnDaemonCommand =
|
||||
| { type: 'run'; reason: RunReason; targetTime?: string; budget?: TurnRunBudget }
|
||||
| { type: 'pause'; reason?: string }
|
||||
| { type: 'resume'; reason?: string }
|
||||
| { type: 'getStatus'; requestId: string }
|
||||
| TurnDaemonMutationCommand;
|
||||
|
||||
export type TurnDaemonCommandResult =
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
}
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
reason: string;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
wasLeader: boolean;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
// 턴 데몬 이벤트는 상태/실행 결과를 API 서버에 알려준다.
|
||||
export type TurnDaemonEvent =
|
||||
| { type: 'status'; requestId?: string; status: TurnDaemonStatus }
|
||||
| { type: 'runStarted'; at: string; reason: RunReason }
|
||||
| { type: 'runCompleted'; at: string; result: TurnRunResult }
|
||||
| { type: 'runFailed'; at: string; error: string }
|
||||
| { type: 'commandResult'; result: TurnDaemonCommandResult };
|
||||
export type {
|
||||
RunReason,
|
||||
TurnCheckpoint,
|
||||
TurnDaemonCommand,
|
||||
TurnDaemonCommandResult,
|
||||
TurnDaemonEvent,
|
||||
TurnDaemonState,
|
||||
TurnDaemonStatus,
|
||||
TurnRunBudget,
|
||||
TurnRunResult,
|
||||
} from '@sammo-ts/common';
|
||||
|
||||
export interface TurnDaemonCommandEnvelope {
|
||||
requestId: string;
|
||||
|
||||
@@ -228,10 +228,12 @@ export class TurnDaemonLifecycle {
|
||||
this.stopping = true;
|
||||
return;
|
||||
case 'getStatus': {
|
||||
await this.commandResponder?.publishStatus(
|
||||
command.requestId,
|
||||
this.getStatus()
|
||||
);
|
||||
if (command.requestId) {
|
||||
await this.commandResponder?.publishStatus(
|
||||
command.requestId,
|
||||
this.getStatus()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 'run':
|
||||
@@ -285,7 +287,7 @@ export class TurnDaemonLifecycle {
|
||||
} as TurnDaemonCommandResult;
|
||||
}
|
||||
|
||||
if (this.commandResponder) {
|
||||
if (this.commandResponder && command.requestId) {
|
||||
await this.commandResponder.publishCommandResult(
|
||||
command.requestId,
|
||||
result
|
||||
|
||||
@@ -1,78 +1,22 @@
|
||||
export type TurnDaemonState = 'idle' | 'running' | 'flushing' | 'paused' | 'stopping';
|
||||
import type {
|
||||
TurnCheckpoint,
|
||||
TurnDaemonCommand,
|
||||
TurnDaemonCommandResult,
|
||||
TurnDaemonStatus,
|
||||
TurnRunBudget,
|
||||
TurnRunResult,
|
||||
} from '@sammo-ts/common';
|
||||
|
||||
export type RunReason = 'schedule' | 'manual' | 'poke';
|
||||
|
||||
export interface TurnRunBudget {
|
||||
budgetMs: number;
|
||||
maxGenerals: number;
|
||||
catchUpCap: number;
|
||||
}
|
||||
|
||||
export interface TurnCheckpoint {
|
||||
turnTime: string;
|
||||
generalId?: number;
|
||||
year: number;
|
||||
month: number;
|
||||
}
|
||||
|
||||
export interface TurnRunResult {
|
||||
lastTurnTime: string;
|
||||
processedGenerals: number;
|
||||
processedTurns: number;
|
||||
durationMs: number;
|
||||
partial: boolean;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export interface TurnDaemonStatus {
|
||||
state: TurnDaemonState;
|
||||
running: boolean;
|
||||
paused: boolean;
|
||||
lastError?: string;
|
||||
lastRunAt?: string;
|
||||
lastDurationMs?: number;
|
||||
lastTurnTime?: string;
|
||||
nextTurnTime?: string;
|
||||
pendingReason?: RunReason;
|
||||
queueDepth: number;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export type TurnDaemonCommand =
|
||||
| { type: 'run'; reason: RunReason; targetTime?: string; budget?: TurnRunBudget }
|
||||
| { type: 'pause'; reason?: string }
|
||||
| { type: 'resume'; reason?: string }
|
||||
| { type: 'shutdown'; reason?: string }
|
||||
| { type: 'getStatus'; requestId: string }
|
||||
| { type: 'troopJoin'; requestId: string; generalId: number; troopId: number }
|
||||
| { type: 'troopExit'; requestId: string; generalId: number };
|
||||
|
||||
export type TurnDaemonCommandResult =
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
}
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
reason: string;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
wasLeader: boolean;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
reason: string;
|
||||
};
|
||||
export type {
|
||||
RunReason,
|
||||
TurnCheckpoint,
|
||||
TurnDaemonCommand,
|
||||
TurnDaemonCommandResult,
|
||||
TurnDaemonState,
|
||||
TurnDaemonStatus,
|
||||
TurnRunBudget,
|
||||
TurnRunResult,
|
||||
} from '@sammo-ts/common';
|
||||
|
||||
export interface TurnDaemonCommandHandler {
|
||||
handle(command: TurnDaemonCommand): Promise<TurnDaemonCommandResult | null>;
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from './util/RNG.js';
|
||||
export * from './util/RandUtil.js';
|
||||
export * from './util/TestRNG.js';
|
||||
export * from './util/sha512.js';
|
||||
export * from './turnDaemon/types.js';
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
export type TurnDaemonState =
|
||||
| 'idle'
|
||||
| 'running'
|
||||
| 'flushing'
|
||||
| 'paused'
|
||||
| 'stopping';
|
||||
|
||||
export type RunReason = 'schedule' | 'manual' | 'poke';
|
||||
|
||||
export interface TurnRunBudget {
|
||||
budgetMs: number;
|
||||
maxGenerals: number;
|
||||
catchUpCap: number;
|
||||
}
|
||||
|
||||
export interface TurnCheckpoint {
|
||||
turnTime: string;
|
||||
generalId?: number;
|
||||
year: number;
|
||||
month: number;
|
||||
}
|
||||
|
||||
export interface TurnRunResult {
|
||||
lastTurnTime: string;
|
||||
processedGenerals: number;
|
||||
processedTurns: number;
|
||||
durationMs: number;
|
||||
partial: boolean;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export interface TurnDaemonStatus {
|
||||
state: TurnDaemonState;
|
||||
running: boolean;
|
||||
paused: boolean;
|
||||
lastError?: string;
|
||||
lastRunAt?: string;
|
||||
lastDurationMs?: number;
|
||||
lastTurnTime?: string;
|
||||
nextTurnTime?: string;
|
||||
pendingReason?: RunReason;
|
||||
queueDepth: number;
|
||||
checkpoint?: TurnCheckpoint;
|
||||
}
|
||||
|
||||
export type TurnDaemonCommand =
|
||||
| {
|
||||
type: 'run';
|
||||
reason: RunReason;
|
||||
targetTime?: string;
|
||||
budget?: TurnRunBudget;
|
||||
}
|
||||
| { type: 'pause'; reason?: string }
|
||||
| { type: 'resume'; reason?: string }
|
||||
| { type: 'shutdown'; reason?: string }
|
||||
| { type: 'getStatus'; requestId?: string }
|
||||
| { type: 'troopJoin'; requestId?: string; generalId: number; troopId: number }
|
||||
| { type: 'troopExit'; requestId?: string; generalId: number };
|
||||
|
||||
export type TurnDaemonCommandResult =
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
}
|
||||
| {
|
||||
type: 'troopJoin';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
troopId: number;
|
||||
reason: string;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: true;
|
||||
generalId: number;
|
||||
wasLeader: boolean;
|
||||
}
|
||||
| {
|
||||
type: 'troopExit';
|
||||
ok: false;
|
||||
generalId: number;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
export type TurnDaemonEvent =
|
||||
| { type: 'status'; requestId?: string; status: TurnDaemonStatus }
|
||||
| { type: 'runStarted'; at: string; reason: RunReason }
|
||||
| { type: 'runCompleted'; at: string; result: TurnRunResult }
|
||||
| { type: 'runFailed'; at: string; error: string }
|
||||
| { type: 'commandResult'; result: TurnDaemonCommandResult };
|
||||
Reference in New Issue
Block a user