← Docs hub

MainApi TaskManager Insertion

이 문서는 기존 DeviceAgent에서 명령이 MainApi.executeMethod(...)로 모이던 구조와, 그 위치에 TaskManager가 어떻게 삽입되는지를 설명한다.

핵심은 아래 한 줄이다.

기존 method/Bundle 진입점은 유지하되, MainApi 안에서 TaskManager가 task control path와 legacy execution path를 공통 관리한다.

MainApi TaskManager Insertion

1. 기존 명령 집결 위치

기존 DeviceAgent 실행 흐름은 기능별 source가 달라도 결국 MainApi.executeMethod(method, indata, outdata)로 모이는 구조다.

대표 source:

Source 의미
Voice / On-device Bridge 음성 명령을 token 또는 method/Bundle로 변환해 DeviceAgent에 전달
App / Remote 앱 버튼, 원격 제어, 예약 실행 등
MQTT / Server Command 서버에서 내려오는 원격 명령
Internal Schedule / Policy DeviceAgent 내부 예약, 자동화, 정책 트리거

기존 구조에서는 이 source들이 모이면 MainApi.executeMethodInternal(...) 내부의 큰 method 분기와 domain manager 호출로 내려갔다.

source -> DeviceAgent entry -> MainApi.executeMethod -> executeMethodInternal -> command/domain/service

2. 변경된 삽입점

현재 변경 구조는 MainApi.executeMethod(...) 안에서 두 단계로 나뉜다.

if (TaskManager.getInstance().handleControlMethod(method, indata, outdata,
        (taskMethod, taskInput, taskOutput) -> () -> executeMethodInternal(taskMethod, taskInput, taskOutput))) {
    return;
}
TaskManager.getInstance().executeLegacy(method, indata, outdata,
        () -> executeMethodInternal(method, indata, outdata));

의미:

단계 동작 결과
1 handleControlMethod(...) submitTask, submitWorkflow, getTaskStatus, cancelTask, getDevicePlanningContext 같은 TaskManager API면 여기서 처리하고 종료
2 executeLegacy(...) 기존 method면 TaskManager가 실행 record/event/policy wrapper를 씌운 뒤 기존 executeMethodInternal(...)로 위임
3 executeMethodInternal(...) 기존 MainApi 내부 분기와 domain handler는 최대한 유지

즉 TaskManager는 기존 MainApi를 대체하는 것이 아니라, MainApi의 진입점에서 task-aware 실행 관문 역할을 한다.

3. TaskManager가 잡는 명령군

TaskManager.handleControlMethod(...)가 직접 처리해야 하는 명령은 “기능 실행 method”가 아니라 “task/workflow 관리 method”다.

Method 역할
submitTask 단일 task 등록/실행
submitWorkflow 여러 subTask를 workflow로 등록/순차 또는 일부 병렬 실행
getTaskStatus 특정 task 상태 조회
listTasks task 목록 조회
getQueueStatus queue 상태 조회
cancelTask task/workflow 취소
getTaskManagerStatus TaskManager 내부 상태 조회
getDevicePlanningContext planning 전 기기 상태 snapshot 조회
classifyTaskIngress ingress payload가 task/control/progress/event 중 무엇인지 분류

반대로 setAirCleanerOperation, setMoveTo, returnToStation, setChangeLlmStatus 같은 실제 기능 method는 executor 또는 legacy wrapper를 통해 기존 domain logic으로 내려간다.

4. 기존 method가 TaskManager로 들어오는 방식

복합명령에서 Cloud/On-device/MQTT가 바로 setAirCleanerOperation을 여러 번 호출하는 구조는 지양한다.

권장 구조:

submitWorkflow
  subTasks[0].taskMethod = setMoveTo
  subTasks[1].taskMethod = setAirCleanerOperation

DeviceAgent 내부에서는:

  1. MainApi.executeMethod("submitWorkflow", bundle, outdata)로 진입한다.
  2. TaskManager.handleControlMethod(...)submitWorkflow를 잡는다.
  3. TaskManager가 subTask 순서, queue, 현재 step, 실패 reason을 관리한다.
  4. 각 subTask 실행 시점에 executeMethodInternal(taskMethod, taskInput, taskOutput) 또는 등록 executor를 호출한다.
  5. 기존 MainApi/domain handler는 실제 동작 조건과 실행을 담당한다.

5. 왜 이 위치가 중요한가

TaskManager를 MainApi 바깥 source별 adapter에만 두면 Cloud, MQTT, App, 예약마다 실행 정책이 갈라진다.

반대로 MainApi.executeMethod(...) 안에 공통 hook을 두면:

효과 설명
source 통합 Cloud/MQTT/App/예약/로컬 음성이 모두 같은 task contract를 탄다
legacy 보존 기존 method 분기와 domain logic을 크게 뜯지 않는다
복합명령 가능 submitWorkflow가 여러 기존 method를 step으로 묶는다
이벤트 통합 step started/completed/failed를 onTaskEvent로 공통 발행
replan 경계 명확화 정상 progress/completed는 로컬 처리, requires_cloud_decision=true 실패만 상위 판단 후보가 된다

6. 업체 구현 시 체크포인트

체크포인트 기준
MainApi hook 모든 외부 method가 executeMethod(...)에 들어오면 TaskManager hook을 먼저 통과해야 함
Task API 분리 submitTask/submitWorkflow 같은 control method와 실제 device method를 구분해야 함
Legacy wrapper 기존 method도 최소한 task record/event wrapper로 감싸야 source trace와 상태 추적 가능
Executor binding taskMethod를 기존 domain handler 또는 TaskExecutorRegistry에 연결해야 함
Event payload taskId, workflowId, eventName, method, status, reason_code를 공통으로 제공해야 함
Context snapshot planning 전에는 getDevicePlanningContext로 현재 상태를 제공해야 함