canon draft¶
함수 가이드
이 함수는 hive alpha 와 storgate beta 에 종속된다.
접수된 작업은 storgate 작업목록 으로 관리된다. storgate beta 가 비활성이라면 접수할 수 없다.
/usr/local/m2/setting.json 다음 영역에 대해 기술한다.
{
"functions": {
"contents": {
"canon": {
...
}
}
}
}
canon 은 부적합 원본을 규격 적합 자산으로 정규화하는 것 으로 Conformant Asset Normalization Of Nonconformant sources 의 약어이다.
Note
쉽게 말해 웹 표준이 아닌 소스(예. WEBM · VP9 · MP3 )를 표준 규격(예. MP4 · AVC1 · AAC )으로 변환해 원본 스토리지에 적재하는 역할을 수행한다.
canon의 목적은 다음과 같다.
파편화된 미디어 자산 정규화
미디어 자산 호환성 강화
저장용량 절감 및 재배치
트랜스코딩 최소화
Important
이 함수의 프로파일 은 profiles 를 의미하며, variant가 없는 단일 형식을 지칭한다.
산출물은 온전한 mp4 single container 다.
프로파일의 fmp4 rendition 은 코덱 · 해상도 · 프레임레이트 규격과 세그먼트 트랜스코딩 방식 을 제공하며,
세그먼트를 병합해 최종 mp4 로 만든다.
canon 은 원본을 처음부터 다시 인코딩하지 않는다.
hive alpha 가 이미 트랜스코딩해 둔 세그먼트는 그대로 재사용하고,
누락된 세그먼트만 개별로 트랜스코딩한 뒤 전체를 하나의 mp4 로 병합한다.
이 방식에서 다음 성질이 따라온다.
작업 단위가 세그먼트이므로 transcoder 의
timeout은 세그먼트 1개 기준이다. 작업 전체 소요시간은 상태 메시지 의timestamps.normalize로 확인한다.누락 세그먼트가 없으면 트랜스코딩 없이 병합만 수행하며
result.method가remux가 된다.재생이 선행된 콘텐츠일수록 재사용할 세그먼트가 많아 비용이 낮다. mezzanine 의
onIdle위임이 이 성질을 이용한다.
How to use¶
트랜스코딩은 대표적인 LRO(Long Running Operation)다. 작업(job)을 등록하고 완료를 통지(callback)받는 메커니즘으로 동작한다.
Method |
URL |
정상응답 |
설명 |
|---|---|---|---|
|
|
|
트랜스코딩 작업을 생성 |
|
|
|
트랜스코딩 작업상태를 조회 |
|
|
|
트랜스코딩 작업을 취소 |
실패 응답은 각 절의 에러 응답 항목에 정리한다.
작업 생성¶
본문에 원본 · 프로파일 · 적재 대상을 명시한다.
POST /vfly/v1/normalize/jobs HTTP/1.1
Host: example.com
Content-Type: application/json
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "canonarchive" ],
"delete": [ "originstorage" ],
"callback": "https://ops.example.com/hook/canon"
}
origin정규화 대상 원본 URL
profile정규화 프로파일 이름
dest적재 대상. endpoints 의
name배열이다. 항목 수만큼 적재하며 생략할 수 없다. 암묵적인 적재 위치는 없다.delete삭제 대상.
dest와 같은 형식이며 생략할 수 있다. 모든 적재가 성공한 뒤에만 수행한다.callback완료 통보를 받을 URL. 생략하면 통보 없이 처리한다.
Important
트랜스코딩은 소요시간이 길기 때문에 canon 함수는 요청을 접수만 하고 202 Accepted 를 응답한다.
접수된 작업은 storgate 작업목록 에 적재되어 수행된다.
처리 결과는 callback 으로 통보한다.
요청을 수락하면 작업 ID 를 발급한다. Location 헤더가 상태 조회 URL 을 가리킨다.
응답 본문은 상태 메시지 의 subset 이며,
접수 시점에 확정된 필드까지만 채워진다.
HTTP/1.1 202 Accepted
Location: /vfly/v1/normalize/jobs/9f2c41ab7d0e5b38
Content-Type: application/json
{
"meta": {
"vhost": "example.com",
"event": "canon",
"profile": "my_standard_profile",
"timestamps": {
"accept": "2026-07-30T10:15:45.256Z"
}
},
"result": {
"id": "9f2c41ab7d0e5b38",
"status": "accepted",
"src": {
"url": "https://videofly.co.kr/dir/sample.mkv"
}
}
}
필드 정의는 상태 메시지 를 따른다.
적재 경로¶
적재 대상은 dest 로 명시 한다.
원본 경로에 덮어쓰려면 원본 스토리지를 가리키는 엔드포인트 를 선언한다.
정규화와 병합은 요청당 1회이고 적재만 N회이므로, 적재 대상을 늘려도 트랜스코딩 비용은 늘지 않는다.
delete는 모든 적재가 성공한 뒤에만 수행한다. 선언 순서와 무관하다. 적재가 하나라도 실패하면 삭제하지 않는다 — 원본이 유실되는 것을 막기 위한 규칙이다.
에러 응답¶
접수하지 못하면 본문 없이 실패를 응답한다.
응답 |
실패 원인 |
|---|---|
|
본문 형식 오류 · |
|
meta 의 |
|
transcoder 장애등 서비스 구동상 장애 |
Note
접수 단계의 실패는 위 응답 코드로만 전달된다. 접수 이후 처리 단계의 실패는 응답 코드가 아니라
상태 메시지 의 failed 로 통보된다.
상태 조회 · 취소¶
발급된 ID 로 진행 상태를 조회하거나 작업을 취소한다.
# 상태 조회
GET https://videofly.co.kr/vfly/v1/normalize/jobs/9f2c41ab7d0e5b38
# 취소
DELETE https://videofly.co.kr/vfly/v1/normalize/jobs/9f2c41ab7d0e5b38
조회 · 취소의 응답 본문도 상태 메시지 의 subset 이다.
진행 정도에 따라 채워지는 범위만 다르며, status 는 다음 값을 가진다.
상태 |
설명 |
|---|---|
|
접수되었으나 아직 시작하지 않았다. |
|
정규화가 진행 중이다. |
|
정규화하여 적재했다. |
|
정규화하지 않았다. |
|
정규화하지 못했다. |
|
취소되었다. |
정상 처리는 200 OK 로 응답한다.
Note
취소된 작업은 callback 을 통보하지 않는다.
작업목록은 storgate beta 가 유지한다. 노드가 재시작되어도 조회 · 취소가 유지되어야 한다면 database draft 모드를 권장한다.
에러 응답¶
응답 |
의미 |
|---|---|
|
ID 가 없거나 작업 저장기간이 만료되었다. |
|
이미 종료된 작업이라 취소할 수 없다 ( |
callback¶
callback 은 접수 본문의 callback 필드로 등록하며, API 로 직접 접수한 요청 에만 해당한다.
트랜스코딩/정규화가 종료되면 ( 성공 · 실패 · 생략 모두 ) 이 URL 로 통보한다.
항목 |
규격 |
|---|---|
메서드 |
|
|
|
성공 판정 |
|
Warning
callback 요청에는 서명 · 인증이 없다. 수신 엔드포인트는 접근 제어를 자체적으로 구성한다.
통보 본문은 상태 메시지 구조를 따른다.
재시도¶
수신측 응답 |
판정 |
동작 |
|---|---|---|
|
성공 |
종료한다. |
|
일시 실패 |
지수 백오프로 재시도한다. |
그 외 |
영구 실패 |
재시도하지 않고 로그에 기록한다. |
무응답 · 연결 실패 |
일시 실패 |
지수 백오프로 재시도한다. |
Note
callback 전달 실패는 정규화 실패가 아니다. 정본은 이미 적재되어 있으므로 재생에는 영향이 없다. 통보를 놓친 대상은 onBatch 로 재확인한다.
상태 메시지¶
작업의 상태를 표현하는 단일 메시지 구조 다. 작업 생성 · 상태 조회 · 취소 의 응답 본문과 callback 의 통보 본문은 모두 이 구조의 subset 이며, 시점에 따라 채워지는 범위만 다르다.
Warning
draft 개발 단계에서 가능한 상세한 정보를 보강한다.
아래는 정규화하여 적재한 경우다.
{
"meta": {
"vhost": "example.com",
"event": "canon",
"profile": "my_standard_profile",
"timestamps": {
"accept": "2026-07-30T10:15:45.256Z",
"normalize": {
"start": "2026-07-30T10:15:46.001Z",
"end": "2026-07-30T10:18:12.874Z"
}
}
},
"result": {
"id": "9f2c41ab7d0e5b38",
"status": "completed",
"method": "transcode",
"src": {
"url": "https://videofly.co.kr/video.mkv",
"videoId": "c81d4e2ebf3a",
"container": "mkv",
"video": { "codec": "vp9", "resolution": "1920x1080", "frame_rate": 29.97 },
"audio": { "codec": "opus", "channels": 2 },
"duration": 372.44,
"size": 284917263
},
"asset": {
"container": "mp4",
"video": { "codec": "h264", "resolution": "1920x1080", "frame_rate": 29.97 },
"audio": { "codec": "aac", "channels": 2 },
"size": 198432110
},
"dest": [
{
"url": "s3://s3-canon-archive/test/123/sample.mp4",
"storage": "canonarchive"
},
{
"url": "s3://s3-canon-backup/test/123/sample.mp4",
"storage": "canonbackup"
}
],
"deleted": [
{
"url": "s3://origin-bucket/dir/sample.mkv",
"storage": "originstorage"
}
]
}
}
meta요청 컨텍스트. 웹훅 개발가이드 와 같은 구조를 따른다.
timestamps.accept수락 시각timestamps.normalize정규화 시작 · 종료 시각.status가failed면end는 실패를 확정한 시각이다.skipped면 항목 자체가 생략된다.
result.id작업 생성 에서 발급한 작업 ID
result.status종료 상태. 상태 조회 · 취소 의
status와 같은 값 집합이며, 종료 시점에 통보되는 값은 아래 세 가지다.상태
설명
completed정규화하여 모든 적재 · 삭제에 성공했다.
asset·dest가 포함된다.skipped정규화하지 않았다.
reason이 포함된다.failed정규화하지 못했거나 적재 · 삭제 중 하나 이상이 실패했다.
error가 포함된다.Note
대상이 여러 곳일 때 하나라도 실패하면 ``failed`` 다. 부분 성공 상태는 없다. 성공한 작업은
dest·deleted에 그대로 남으므로 어디까지 처리됐는지는 항목별로 확인한다.result.method사용한 수단.
skipped·failed면null이다.remux누락 세그먼트가 없어 병합만 수행했다.transcode누락 세그먼트를 하나 이상 트랜스코딩했다.
result.src정규화 입력. 세 상태 모두 포함되지만 채워지는 범위가 다르다.
url·videoId는 항상 포함된다.container·video·audio·duration·size는 원본 분석에 성공한 경우에만 포함된다.error.phase가fetch·probe면 분석 이전 단계의 실패이므로 이 필드들이 없다.
video·audio필드명은 video 규격을 따른다.result.asset정규화 출력의 규격. 산출물은 요청당 1개이므로 단일 객체다.
container·video·audio·size를 가지며 적재를 시도한 경우 포함된다.result.dest적재 위치 배열. 접수 본문의
dest에 선언한 수만큼 항목이 생긴다. 적재를 시도한 경우 포함되므로status가failed여도 성공분이 남는다.url적재 위치. 스킴을 포함한 절대 표현이며 endpoints 의
domain에 따라 형식이 갈린다.domainurlnull( AWS S3 )s3://{bucket}/{path}지정됨 ( S3 호환 )
https://{domain}/{bucket}/{path}Warning
적재 위치의 식별 표현이며 접근 가능한 URL 이 아니다. 버킷이 비공개면 이 주소로 조회할 수 없다. 자격증명 · 쿼리스트링은 포함하지 않는다.
storage적용된 endpoints 의
nameerror이 항목의 적재가 실패한 경우에만 포함된다.
reason·message를 가진다. 항목별 실패이므로phase는 갖지 않는다 — 작업 전체의 단계는result.error.phase가store로 표시한다.
result.deleted삭제 위치 배열. 접수 본문의
delete에 선언한 수만큼 항목이 생기고, 선언이 없으면 필드 자체가 없다. 항목 구성은dest와 같다 (url·storage, 실패 시error).적재가 하나라도 실패하면 삭제를 수행하지 않으므로 이 필드도 없다.
정규화하지 않은 경우 asset · dest 대신 reason 이 포함된다.
{
"meta": {
"vhost": "example.com",
"event": "canon",
"profile": "my_standard_profile",
"timestamps": {
"accept": "2026-07-30T10:15:45.256Z"
}
},
"result": {
"id": "3a7e02c9d4f1b865",
"status": "skipped",
"method": null,
"src": {
"url": "https://videofly.co.kr/video.mp4",
"videoId": "a1b2c3d4e5f6",
"container": "mp4",
"video": { "codec": "h264", "resolution": "1280x720", "frame_rate": 30 },
"audio": { "codec": "aac", "channels": 2 },
"duration": 128.5,
"size": 41230776
},
"reason": "already_conformant"
}
}
result.reasonskipped사유.사유
설명
already_conformant원본이 이미 프로파일 규격을 만족한다.
Note
판정은 경로의 확장자가 아니라 원본을 분석한 결과 로 한다. 원본 경로에 덮어쓴 경우 확장자와 내용이 어긋나 있으므로(
.mkv경로에 MP4 콘텐츠 ) 확장자를 기준으로 삼으면 이미 정규화된 자산을 계속 다시 정규화한다.
실패한 경우 error 가 포함된다. 아래는 정규화 단계에서 실패해 적재를 시도하지 못한 예다.
error.phase 가 store 라면 asset · dest 도 함께 포함되며 실패한 항목에 dest[].error 가 담긴다.
{
"meta": {
"vhost": "example.com",
"event": "canon",
"profile": "my_standard_profile",
"timestamps": {
"accept": "2026-07-30T10:15:45.256Z",
"normalize": {
"start": "2026-07-30T10:15:46.001Z",
"end": "2026-07-30T10:25:46.113Z"
}
}
},
"result": {
"id": "9f2c41ab7d0e5b38",
"status": "failed",
"method": null,
"src": { ... },
"error": {
"phase": "normalize",
"reason": "transcoder_timeout",
"message": "no response in 600s"
}
}
}
error.phase실패 단계
단계
상세
fetch원본 획득 실패
probe원본 분석 실패
normalize대상 정규화 실패
store대상 적재 실패
delete대상 삭제 실패
Note
fetch·probe는 분석 이전 단계의 실패이므로skipped가 아니라failed로 통보한다.skipped는 분석에 성공했고 그 결과가 “정규화 불필요” 인 경우다.error.reason실패 사유 식별자
error.message실패 사유 설명
meta¶
"meta": {
"enable": false,
"keyword": "vfly/v1/normalize",
"expose": false
}
enable (기본: false)활성화
keyword (기본: vfly/v1/normalize)Normalize 작업 명령을 인식하는 URL 키워드. 이 키워드 이후 경로가 canon 명령으로 해석된다.
expose (기본: false)외부 인터페이스 노출 여부.
false인 경우403 Forbidden으로 응답한다.Note
내부적으로 발견된 파일을 처리하는 경우가 많다.
hive alpha 에 의해 서비스된 URL ( mezzanine 의
onIdle)onBatch 에 의해 traverse된 URL
이 경로들은 API 를 경유하지 않고 같은 가상호스트 안에서 inline 으로 연결되므로
expose값과 무관하게 동작하며, callback 도 사용하지 않는다.
transcoder¶
트랜스코더를 구성한다.
"transcoder": {
"type": "local",
"timeout": 60
}
type (기본: local)트랜스코더 타입.
local개발목적의 동시성 1의 트랜스코더로, GPU/CPU 모드를 자동으로 설정한다.hlseg-transcoder={name}사용할 hlseg-transcoder 의name을 연결한다."transcoder": { "type": "hlseg-transcoder=batch", "timeout": 60 }
videofly 가 비활성화되어 있거나 hlseg-transcoder 연결이 유효하지 않다면 요청이 실패한다.
timeout (기본: 60)세그먼트 1개 의 요청전송 후 완료 응답을 기다리는 최대 시간(초). 작업 전체의 제한시간이 아니다.
Note
hlseg-transcoder 는 전송·취합(aggregation) 담당이며, 응답 대기·대응 정책은 본 가상호스트 설정이 소유한다.
로그¶
hlseg-transcoder 트랜잭션은 전역로그인 log 에 기록된다.
access.log 의
x-ctx-id와 log 의x-ctx-id는 동일하다.
설정예제¶
원본 /dir/sample.mkv ( WEBM 계열 · VP9 · Opus ) 를 mp4 ( AVC1 · AAC ) 로 정규화하는 다섯 가지 경우다.
뒤로 갈수록 앞의 설정에 하나씩 더한다.
모든 예제는 aws_s3 엔드포인트를 함께 구성한다.
적재 대상은 항상 접수 본문의
dest로 명시한다. 암묵적인 적재 위치는 없다.
모든 예제는 프로파일 my_standard_profile 을 사용한다.
프로파일은 profiles 에 정의하며 fmp4 rendition 이 기준 규격이 된다.
Note
예제는 기본값과 같은 항목을 생략 했다. 실제 설정에서도 적지 않아도 된다. 생략된 항목의 기본값은 meta · transcoder · endpoints 를 참고한다.
See also
여기서는 URL 로 개별 자산을 정규화한다.
저장소를 순회하며 일괄 정규화 하는 구성은 비디오 정규화 배치 를 참고한다.
이 경우 적재는 storgate beta 의 savePath 가 담당한다.
1. 원본 경로에 덮어쓴다¶
가장 단순한 형태다. 산출물이 원본을 대체하고 경로는 그대로 유지된다.
설정 예제는 아래와 같다.
# functions.contents.canon
"canon": {
"meta": {
"enable": true,
# API 로 직접 호출하므로 노출을 허용한다. 기본값은 false 이며 403 을 응답한다.
"expose": true
},
"transcoder": {
# 기본값 local 은 개발 목적이므로 운영은 task 를 연결한다.
"type": "hlseg-transcoder=batch"
}
}
# functions.backend.aws_s3
# 원본 스토리지다. path 를 지정하지 않으면 입력된 경로 그대로 올린다. 즉 원본을 덮어쓴다.
"endpoints": [
{
"name": "originstorage",
"bucket": "origin-bucket",
"region": "ap-northeast-2"
}
]
접수 요청은 다음과 같다. 덮어쓰기도 dest 로 명시한다.
POST /vfly/v1/normalize/jobs HTTP/1.1
Host: example.com
Content-Type: application/json
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "originstorage" ],
"callback": "https://ops.example.com/hook/canon"
}
결과는 다음과 같다.
# callback 상태 메시지의 result ( 발췌 )
"result": {
"status": "completed",
"method": "transcode",
"asset": {
"container": "mp4",
"video": { "codec": "h264", "resolution": "1920x1080", "frame_rate": 29.97 },
"audio": { "codec": "aac", "channels": 2 },
"size": 198432110
},
"dest": [
{
# 원본 경로 그대로다.
"url": "s3://origin-bucket/dir/sample.mkv",
"storage": "originstorage"
}
]
}
Warning
경로가 .mkv 인데 내용은 MP4 다. 확장자와 내용이 어긋나도 되는 환경에서만 쓴다.
확장자를 맞추려면 2번을 따른다.
2. 같은 디렉터리에 mp4 로 저장한다¶
확장자를 .mp4 로 바꿔 저장한다. 원본 /dir/sample.mkv 는 그대로 남는다.
경로를 바꾸려면 aws_s3 엔드포인트에 경로 규칙을 정의한다. 1번 설정에 다음을 추가한다.
# functions.backend.aws_s3
"aws_s3": {
"meta": {
"enable": true
},
"endpoints": [
{
"name": "samebucket",
# 원본과 같은 버킷이다.
"bucket": "origin-bucket",
"region": "ap-northeast-2",
# /dir/sample.mkv 를 /dir/sample.mp4 로 바꾼다.
# #1 은 pattern 의 첫 캡처그룹( sample )이다.
"path": {
"dest": {
"type": "rewrite",
"urlRewrites": [
{ "pattern": "/dir/(.*)\\.mkv", "replace": "/dir/#1.mp4" }
]
}
},
# 지정하지 않으면 S3 에서 application/octet-stream 으로 내려간다.
# inheritContentType 으로 승계하면 원본의 mkv 타입이 붙으므로 static 으로 고정한다.
"metadata": [
{ "key": "Content-Type", "type": "static", "value": "video/mp4" }
]
}
]
}
접수 요청은 다음과 같다.
POST /vfly/v1/normalize/jobs
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "samebucket" ]
}
결과는 다음과 같다.
"result": {
"status": "completed",
"method": "transcode",
"asset": { "container": "mp4", "size": 198432110 },
"dest": [
{
# path.dest 규칙이 적용된 경로다.
"url": "s3://origin-bucket/dir/sample.mp4",
# 적용된 엔드포인트 이름이다.
"storage": "samebucket"
}
]
}
Note
원본과 산출물이 모두 남으므로 저장용량이 늘어난다. 원본을 정리하려면 5번을 따른다.
3. 다른 저장소에 저장한다¶
버킷과 경로를 모두 바꿔 /test/123/sample.mp4 로 저장한다.
2번과 달라지는 것은 엔드포인트의 bucket 과 replace 뿐이다.
# functions.backend.aws_s3
"endpoints": [
{
"name": "canonarchive",
# 다른 버킷이다.
# AWS 가 아닌 S3 호환 스토리지라면 domain 을, 다른 계정이라면 accessKey · secretKey 를 더한다.
"bucket": "s3-canon-archive",
"region": "ap-northeast-2",
# /dir/sample.mkv 를 /test/123/sample.mp4 로 바꾼다.
"path": {
"dest": {
"type": "rewrite",
"urlRewrites": [
{ "pattern": "/dir/(.*)\\.mkv", "replace": "/test/123/#1.mp4" }
]
}
},
"metadata": [
{ "key": "Content-Type", "type": "static", "value": "video/mp4" }
]
}
]
접수 요청은 다음과 같다.
POST /vfly/v1/normalize/jobs
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "canonarchive" ]
}
결과는 다음과 같다.
"result": {
"status": "completed",
"dest": [
{
"url": "s3://s3-canon-archive/test/123/sample.mp4",
"storage": "canonarchive"
}
]
}
4. 원본 경로와 다른 저장소에 동시에 저장한다¶
dest 에 두 개를 선언하면 두 곳에 적재한다.
원본 경로에도 적재하려면 원본 스토리지를 가리키는 엔드포인트를 따로 정의 해야 한다.
엔드포인트를 두 개 구성한다.
# functions.backend.aws_s3
"endpoints": [
{
# 원본 스토리지다. path 를 지정하지 않으면 입력된 경로 그대로 올린다.
# 즉 /dir/sample.mkv 를 덮어쓴다.
"name": "originstorage",
"bucket": "origin-bucket",
"region": "ap-northeast-2"
},
{
# 3번과 같은 엔드포인트다.
"name": "canonarchive",
"bucket": "s3-canon-archive",
"region": "ap-northeast-2",
"path": {
"dest": {
"type": "rewrite",
"urlRewrites": [
{ "pattern": "/dir/(.*)\\.mkv", "replace": "/test/123/#1.mp4" }
]
}
},
"metadata": [
{ "key": "Content-Type", "type": "static", "value": "video/mp4" }
]
}
]
접수 요청은 다음과 같다.
POST /vfly/v1/normalize/jobs
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "originstorage", "canonarchive" ]
}
결과는 다음과 같다. dest 항목이 두 개다.
"result": {
"status": "completed",
"asset": { "container": "mp4", "size": 198432110 },
"dest": [
{
"url": "s3://origin-bucket/dir/sample.mkv",
"storage": "originstorage"
},
{
"url": "s3://s3-canon-archive/test/123/sample.mp4",
"storage": "canonarchive"
}
]
}
Important
정규화와 병합은 요청당 1회다. 적재 대상을 늘려도 트랜스코딩 비용은 늘지 않는다.
둘 중 하나라도 실패하면 status 는 failed 이며, 실패한 항목에 dest[].error 가 담긴다.
5. 다른 저장소로 옮기고 원본을 삭제한다¶
3번에 delete 를 더한 형태다. 산출물을 다른 저장소에 적재하고 원본을 정리한다.
설정은 4번과 같다. originstorage 는 적재 대상이 아니라 삭제 대상 으로 쓴다.
접수 요청은 다음과 같다.
POST /vfly/v1/normalize/jobs
{
"origin": "https://videofly.co.kr/dir/sample.mkv",
"profile": "my_standard_profile",
"dest": [ "canonarchive" ],
"delete": [ "originstorage" ]
}
결과는 다음과 같다.
"result": {
"status": "completed",
"asset": { "container": "mp4", "size": 198432110 },
"dest": [
{
"url": "s3://s3-canon-archive/test/123/sample.mp4",
"storage": "canonarchive"
}
],
"deleted": [
{
"url": "s3://origin-bucket/dir/sample.mkv",
"storage": "originstorage"
}
]
}
Warning
삭제는 적재가 모두 성공한 뒤에만 수행한다. 선언 순서와 무관하다.
적재가 하나라도 실패하면 삭제하지 않으며 deleted 필드도 생기지 않는다.
원본이 유실되는 것을 막기 위한 규칙이다.