5.7 워크플로우와 외부 연동 - 작업 큐, 상태 머신, MOS 프로토콜
작업 큐의 원자적 선점과 재시도·상태 설계(동시 워커 실험), REST API 설계 원칙, 뉴스룸 연동 프로토콜 MOS의 구조(포트, 메시지, ACK)와 편집·송출 연동 방식을 정리합니다.
#워크플로우란
MAM에서 워크플로우는 "소재에 어떤 처리를 어떤 순서로 적용하는가" 를 정의한 것입니다.
인제스트 → 분석 → QC → (변환) → 프록시 → 등록 → (승인) → 배포 / 아카이브
각 단계는 독립된 작업(Job) 이고, 워크플로우 엔진이 작업을 순서대로 실행하고 결과에 따라 분기합니다(성공 → 다음, QC 실패 → 담당자 검토 대기).
#작업 큐
작업 큐는 "해야 할 일 목록"입니다. 가장 단순한 구현은 DB 테이블입니다. 다음 문제를 해결해야 합니다.
- 여러 워커가 있을 때 같은 작업을 두 번 가져가면 안 됩니다.
- 워커가 죽으면 작업이 영원히 "실행 중"으로 남으면 안 됩니다.
- 실패한 작업은 간격을 두고 재시도하되 무한 반복하지 않습니다.
- 중요한 작업이 먼저 실행되어야 합니다.
#원자적 선점
"가져갈 작업을 고르는 것"과 "내가 가져갔다고 표시하는 것"을 한 문장으로 처리해야 두 워커가 같은 작업을 잡지 않습니다.
def claim(conn, worker):
row = conn.execute("""
UPDATE job SET status='RUNNING', worker=?, attempts=attempts+1
WHERE id = (SELECT id FROM job
WHERE status='QUEUED' AND run_after <= ?
ORDER BY id LIMIT 1)
RETURNING id""", (worker, time.time())).fetchone()
conn.commit()
return row[0] if row else None
200개 작업을 4개 워커 스레드가 동시에 가져가도록 실행했습니다.
처리 건수: 200 | 중복 처리: 0
워커별 처리: w0=57, w1=38, w2=49, w3=56
중복 없이 모두 처리되었고, 부하도 4개 워커에 나뉘었습니다. 이 방식은 SQLite뿐 아니라 PostgreSQL(SELECT ... FOR UPDATE SKIP LOCKED)에서도 같은 원리로 구현합니다. 별도의 메시지 브로커(RabbitMQ, Redis 등)를 쓰면 이 부분을 대신하지만, 어떤 방식이든 작업 상태의 원본은 DB에 두는 편이 운영과 추적에 유리합니다.
#작업 상태 머신
QUEUED ──선점──▶ RUNNING ──성공──▶ DONE
▲ │
│ 실패 │ (attempts < 최대)
└── run_after = now + 대기(지수 증가) ◀─┤
│ (attempts ≥ 최대)
▼
FAILED ──수동 재처리──▶ QUEUED
| 설계 요소 | 방법 |
|---|---|
| 재시도 | attempts를 기록하고 간격을 두며 반복(예: 30초, 2분, 10분) |
| 지수 백오프 | 실패할수록 대기 시간을 늘려 장애 중인 대상에 부하를 주지 않음 |
| 죽은 워커 | 하트비트(주기적으로 시각 갱신)를 기록하고, 일정 시간 갱신이 없는 RUNNING 작업을 QUEUED로 되돌림 |
| 우선순위 | priority 컬럼 추가(긴급 송출 > 일반 프록시) |
| 작업 유형 분리 | 큐/워커를 kind별로 나눠 변환 작업이 분석 작업을 막지 않게 함 |
| 멱등성 | 같은 작업이 두 번 실행돼도 안전하도록(4장 임시 파일 후 교체) |
#작업 간 의존성
워크플로우는 단계 사이의 데이터 전달이 필요합니다. 분석 결과(기술 메타데이터)를 다음 단계(변환 프로파일 선택)가 읽습니다. 작업 간 큰 데이터는 직접 주고받지 않고 DB와 스토리지를 통해 전달합니다(작업 입력은 소재 ID와 파일 위치 정도의 작은 값).
#REST API 설계
모든 기능을 API로 제공하면 UI, 외부 시스템, 스크립트가 같은 방식으로 MAM을 사용할 수 있습니다. 몇 가지 원칙이 있습니다.
| 원칙 | 예 |
|---|---|
| 오래 걸리는 일은 비동기로 | POST /assets/123/proxy → 202 Accepted + { "jobId": 456 }, GET /jobs/456으로 진행률 조회 |
| 멱등 키 지원 | 같은 요청이 중복 전송돼도 작업이 한 번만 생성되도록 Idempotency-Key 헤더 |
| 목록은 페이지네이션 | 수만 건 응답 금지, 커서 기반 페이지 |
| 오류는 구조화 | { "code": "FILE_TRUNCATED", "message": "파일이 중간에 끊겨 있습니다" } |
| 버전 관리 | /v1/ 경로. 외부 시스템 연동은 호환성이 중요 |
| 권한 | 소재 단위 접근 제어, 외부 시스템용 별도 토큰 |
POST /v1/assets/123/jobs
Content-Type: application/json
Idempotency-Key: 7c9e-ingest-123
{ "kind": "proxy", "profile": "web-360p" }
HTTP/1.1 202 Accepted
{ "jobId": 456, "status": "QUEUED" }
#외부 시스템 연동
MAM은 혼자 동작하지 않습니다. 대표적인 연동 대상은 다음과 같습니다.
| 연동 대상 | 방식 | 설계 포인트 |
|---|---|---|
| 뉴스룸/기사 시스템 | MOS 프로토콜 | 소재 정보를 기사에 연결 |
| 편집 시스템(NLE) | 공유 스토리지 + 플러그인/API, EDL/XML | 편집본을 소재로 재등록 |
| 송출 서버(플레이아웃) | 파일 전송 + 서버 제어 프로토콜 | 송출 포맷 변환, 전송 완료 확인 |
| 아카이브 솔루션 | 제품 API 또는 S3 | 요청-완료 비동기 흐름(6장) |
| AI/분석 서비스 | REST, 큐 | 결과를 구간 메타데이터로 저장 |
| 편성 시스템 | DB/API | 프로그램 정보와 소재 연결 |
#MOS 프로토콜
MOS(Media Object Server) 프로토콜은 뉴스룸 컴퓨터 시스템(NCS) 과 미디어 객체 서버(영상 서버, MAM, 자막기, 스틸 스토어 등) 사이의 표준 통신 규약입니다. 기자가 기사를 쓰면서 영상 소재를 검색해 기사에 붙이고, 그 정보를 서로 주고받기 위한 방식입니다. 공개된 MOS 프로토콜 규격(v2.8.4)에서 확인한 핵심 내용은 다음과 같습니다.
- XML 기반 메시지입니다. 모든 메시지는 루트 태그
<mos>로 시작하고, 이어서mosID(MOS 장비 식별자)와ncsID(NCS 식별자), 그 뒤에 메시지 종류와 데이터가 옵니다. 태그는 대소문자를 구분합니다. - TCP/IP 소켓 두 개를 양방향으로 씁니다.
- Lower Port(기본 10540): NCS가 MOS 장비의 접속을 받는 포트. 미디어 객체 메타데이터(
mosObj등)가 오갑니다. - Upper Port(기본 10541): MOS가 NCS의 접속을 받는 포트. 런다운(Running Order) 관련 메시지가 오갑니다.
- 과거 버전(v2.5 이전)에서는 10520/10521이었으며, 일부 윈도우 환경 문제로 바뀌었습니다. 현재는 벤더가 선택할 수 있지만 한 사이트 안에서는 모두 같은 포트를 써야 합니다.
- Lower Port(기본 10540): NCS가 MOS 장비의 접속을 받는 포트. 미디어 객체 메타데이터(
- 응답이 정의된 메시지는 규격이 정한 응답을 주고받습니다. 예를 들어 미디어 객체 메시지에는
mosAck, 런다운 메시지에는roAck같은 응답이 따릅니다. 모든 메시지에 응답하는 것은 아니며, 응답 메시지 자체에는 다시 응답하지 않습니다. 요청과 응답은 메시지에 들어 있는messageID로 짝을 짓습니다(메시지별 규칙은 규격서를 확인하세요). 선택적으로<heartbeat>로 연결 상태를 확인합니다. mosObj: MOS 장비가 "이런 미디어 객체가 있다"고 NCS에 알리는 메시지입니다. 객체가 생성되면mosObj가 전송되고, 이후 변경될 때UPDATED상태로 다시 전송됩니다. NCS는 이 정보를 목록·검색 화면에 보여 줍니다.- 알 수 없는 태그를 받으면 무시하고 처리를 계속합니다(오류를 내지 않음). 이 덕분에 버전이 달라도 서로 연동이 됩니다.
- 런다운은 Running Order → Story → Item → Object의 계층이며, 각 단계의 고유 ID(UID)가 있습니다. 항목은 방송될 순서대로 전송됩니다.
MAM이 MOS 장비 역할을 한다면, 소재가 등록·변경될 때 mosObj를 NCS에 보내고 NCS의 요청(검색·조회)에 응답하는 MOS 게이트웨이를 별도 모듈로 만드는 방식이 일반적입니다. 게이트웨이를 분리하면 MAM의 내부 구조를 MOS 규격에서 보호할 수 있습니다(2편의 어댑터 분리 원칙).
#편집·송출 연동에서의 공통 원칙
- 원본 소유권을 분명히 합니다. 편집 시스템이 MAM 스토리지의 원본을 직접 수정하지 못하게 하고, 편집 결과는 새 소재로 등록합니다.
- 전송 완료를 확인합니다. 송출 서버로 보낸 파일이 정상적으로 적재되었는지 ACK나 조회 API로 확인합니다.
- 외부 시스템이 느리거나 중단돼도 MAM 전체가 멈추지 않도록 타임아웃과 재시도, 서킷 브레이커를 둡니다.
- 연동 이력(무엇을 언제 어디로 보냈는가)을 남깁니다. 방송 사고 시 원인 추적에 필요합니다.
#정리
- 워크플로우는 작업(Job)들의 순서이고, 작업 큐는 원자적 선점, 상태 머신, 재시도, 멱등성으로 설계합니다.
- API는 비동기 작업, 멱등 키, 구조화된 오류로 설계해 UI와 외부 연동이 같은 인터페이스를 쓰게 합니다.
- MOS는 XML 메시지를 TCP 두 포트(10540/10541 기본)로 주고받고 규격이 정한 응답(ACK)을
messageID로 짝 짓는 방식이며, 게이트웨이 모듈로 분리해 연동합니다.
다음 장에서는 아카이브와 AI 메타데이터를 다룹니다.
#참고 자료
링크는 2026-10-28에 열람이 되는 것을 확인했습니다. 규격과 도구 문서는 개정될 수 있으므로 적용하기 전에 최신 판을 확인하세요.