시작하기
기본 개념
파일이 생성되거나 변경되면 필요한 작업 자동으로 시작하기
업무 환경에서는 새로운 파일이 생성되거나 기존 파일이 수정된 이후 다음 작업이 이어지는 경우가 많습니다.
예를 들어 보고서가 저장되면 검토 시스템으로 전송하고, 데이터 파일이 준비되면 처리 서버에서 분석을 시작하며, 처리 결과가 생성되면 지정된 작업 공간에 결과 파일을 반영할 수 있습니다.
파일 이벤트 자동화는 지정한 장비와 폴더에서 발생하는 파일 변경을 확인하고, 설정한 조건에 맞는 이벤트가 발생하면 다음 작업을 시작하도록 구성하는 기능입니다.

파일 자체가 다음 업무를 시작하는 기준이 되므로, 업무 흐름에 맞춰 파일 생성과 변경을 자동화 조건으로 활용할 수 있습니다.
이벤트 흐름
파일 변경 감지부터 후속 처리까지 자동으로 이어가기
파일 이벤트 자동화는 지정된 위치에서 파일 상태를 확인하고, 설정한 이벤트가 발생하면 연결된 작업을 순서대로 실행합니다.
① 파일 생성 또는 변경
↓
② 파일 이벤트 감지
↓
③ 처리 조건 확인
↓
④ 후속 작업 시작
↓
⑤ 처리 결과 확인
예를 들어 특정 폴더에 새로운 파일이 생성되면 자동으로 대상 시스템으로 파일을 전송하고, 전송이 완료된 후 다음 처리 작업을 실행하도록 구성할 수 있습니다.
File Event
↓
Trigger
↓
File Transfer
↓
Processing
↓
Result
이렇게 파일 변경을 업무 시작점으로 활용하면 파일이 준비되는 시점부터 다음 작업까지 하나의 흐름으로 연결할 수 있습니다.
자동화 효과
파일 상태를 기준으로 다음 작업을 자연스럽게 이어가기
파일 작업이 완료된 후 다음 업무를 시작하는 환경에서는 담당자가 파일 상태를 확인하고 필요한 작업을 실행하는 과정이 반복됩니다.
파일 이벤트 자동화를 활용하면 파일 생성과 변경을 실행 조건으로 설정해, 조건에 맞는 파일이 준비된 시점부터 다음 작업을 이어갈 수 있습니다.
| 구분 | 일반적인 파일 작업 | 파일 이벤트 자동화 |
|---|---|---|
| 작업 시작 | 파일 상태 확인 후 작업 실행 | 파일 이벤트를 기준으로 작업 시작 |
| 대상 확인 | 작업마다 파일과 경로 확인 | 설정된 조건에 맞는 파일 확인 |
| 후속 처리 | 다음 작업을 업무 순서에 따라 실행 | 연결된 작업을 자동 실행 |
| 업무 흐름 | 파일 작업과 다음 업무를 개별 관리 | 파일 이벤트부터 결과까지 연결 |
이벤트 기반 자동화는 파일의 상태 변화를 업무 흐름의 시작점으로 활용해, 파일이 준비된 이후 필요한 작업이 정해진 순서에 따라 이어지도록 구성할 수 있습니다.
IT 엔지니어
파일 이벤트를 감지하고 후속 작업까지 자동화하기
감지 구성
파일 변경을 확인할 장비와 폴더 연결하기
IT 엔지니어는 파일 이벤트를 확인할 장비와 대상 폴더를 자동화 환경에 연결합니다.
파일이 생성되거나 수정되는 Source를 지정하고, 이벤트 발생 후 작업을 실행할 시스템과 대상 위치를 Flow에 연결합니다.

예를 들어 Windows 서버의 /report/input 폴더에서 파일 변경을 감지하고, 이벤트가 발생하면 Linux 처리 서버와 결과 스토리지로 이어지는 흐름을 구성할 수 있습니다.
| 구성 항목 | 설정 내용 |
|---|---|
| 감지 장비 | 파일 변경을 확인할 Device |
| 감지 폴더 | 이벤트를 확인할 파일 경로 |
| 처리 장비 | 이벤트 발생 후 작업을 실행할 시스템 |
| 결과 위치 | 처리 완료 파일이 반영될 작업 공간 |
파일 이벤트를 감지할 환경과 후속 처리 환경을 연결하면 자동화 흐름의 기본 구조가 준비됩니다.
이벤트 조건
작업을 시작할 파일 이벤트와 처리 대상 정하기
감지 환경을 구성한 후에는 어떤 파일 상태 변화를 이벤트로 사용할지 설정합니다.
예를 들어 새 파일이 생성될 때 작업을 시작하거나, 기존 파일이 수정되었을 때 후속 작업을 실행하도록 구성할 수 있습니다.

주요 설정 항목은 다음과 같습니다.
| 설정 항목 | 활용 |
|---|---|
| 감지 이벤트 | 파일 생성 또는 수정 기준 설정 |
| 대상 경로 | 이벤트를 확인할 폴더 지정 |
| 파일 필터 | 이름과 확장자별 처리 대상 설정 |
| 실행 범위 | 이벤트 발생 후 처리할 파일 범위 설정 |
예를 들어 .csv 파일이 새로 생성될 때만 데이터 처리 작업을 시작하거나, report.xlsx 파일이 수정될 때 결과 배포 작업을 실행하도록 구성할 수 있습니다.
이벤트 조건을 구체적으로 설정하면 업무에 필요한 파일 변화를 기준으로 후속 작업을 시작할 수 있습니다.
흐름 연결
파일 변경 후 필요한 작업을 순서대로 연결하기
파일 이벤트가 발생한 후에는 전송, 변환, 저장, 배포 등 필요한 작업을 Flow Canvas에서 연결합니다.
각 작업은 앞선 단계의 실행 결과에 따라 다음 작업으로 이어지도록 구성할 수 있으며, 하나의 파일 이벤트에서 여러 작업이 연결된 처리 흐름을 만들 수 있습니다.
File Created
↓
Filter Check
↓
Transfer
↓
Processing
↓
Result Storage
↓
Next Flow
예를 들어 원본 영상 파일이 생성되면 처리 서버로 전송하고, 변환 작업이 완료되면 결과 파일을 배포 위치에 반영하는 흐름을 구성할 수 있습니다.
실행 확인
단계별 진행 상태와 처리 결과 확인하기
파일 이벤트를 기준으로 실행된 작업은 Runs에서 진행 상태와 처리 결과를 확인할 수 있습니다.
각 실행 기록에서는 어떤 이벤트로 작업이 시작되었는지와 처리 대상 파일, 연결된 작업, 진행률, 실행 상태를 함께 확인합니다.

| 확인 항목 | 확인 내용 |
|---|---|
| Trigger | 작업을 시작한 파일 이벤트 |
| Source | 이벤트가 발생한 장비와 경로 |
| Files | 처리된 파일 |
| Flow | 연결된 작업 흐름 |
| Progress | 단계별 처리 진행률 |
| Status | 현재 또는 완료된 작업 상태 |
실행 결과를 확인하면 이벤트 감지부터 후속 작업까지 각 단계가 설정된 흐름에 따라 처리되었는지 확인할 수 있습니다.
예외 대응
이벤트 감지와 후속 작업 상태를 확인하고 다시 처리하기
추가 확인이 필요한 작업이 발생하면 이벤트 감지 상태와 후속 작업의 실행 기록을 함께 확인합니다.
Runs와 Audit Log에서는 이벤트가 발생한 장비와 파일 경로, Trigger 조건, 처리 대상 파일, 후속 작업의 실행 상태를 확인할 수 있습니다.

실행 상태 확인
↓
이벤트 감지 기록 확인
↓
Trigger 조건 확인
↓
장비 · 경로 · 파일 상태 확인
↓
후속 작업 상태 확인
↓
필요한 설정 조정
↓
작업 재실행
↓
결과 확인
| 확인 항목 | 확인 내용 |
|---|---|
| 이벤트 조건 | 파일 생성·수정 감지 기준 |
| 장비 연결 | 감지 장비와 처리 장비 상태 |
| 파일 경로 | 이벤트 대상 폴더와 파일 위치 |
| 파일 조건 | 필터와 처리 대상 설정 |
| 후속 작업 | 연결된 작업의 실행 상태 |
| 실행 기록 | Run과 Audit Log |
이렇게 파일 이벤트와 후속 작업의 실행 상태를 함께 관리하면, 파일 변경을 시작점으로 전송과 처리, 결과 활용까지 이어지는 자동화 흐름을 업무 환경에 맞춰 운영할 수 있습니다.
개발자
폴더를 감시해 파일이 들어오면 전송과 외부 호출을 자동 실행하기
연동 준비
공통 호출 코드와 경로 표기 준비하기
import os
import requests
BASE_URL = os.getenv("INNORIX_BASE_URL", "https://app.innorix.com").rstrip("/")
TOKEN = os.environ["INNORIX_ACCESS_TOKEN"]
WORKSPACE_ID = os.getenv("INNORIX_WORKSPACE_ID") # optional; falls back to the current workspace
STATUS_COMPLETE = 2
TERMINAL = {2, 4, 5, 9, 99} # complete / error / cancelled / partial / failed
NOT_SUCCEEDED = {4, 5, 9, 99}
def api(method, path, body=None, params=None):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {TOKEN}",
}
if WORKSPACE_ID:
headers["x-workspace-id"] = WORKSPACE_ID
response = requests.request(
method, BASE_URL + path,
headers=headers, json=body, params=params, timeout=30,
)
payload = response.json() if response.content else {}
if not response.ok:
raise RuntimeError(payload.get("message") or f"HTTP {response.status_code}")
return payload.get("data")
def is_terminal(detail):
return detail.get("isTerminal", detail.get("status") in TERMINAL)자동화는 경로를 평문이 아니라 장비 식별자와 base64 경로를 이어 붙인 토큰으로 받습니다.
import base64
def encode_path(device_id, raw_path):
normalized = str(raw_path or "").replace("\\", "/")
token = base64.b64encode(normalized.encode("utf-8")).decode("ascii")
return f"{device_id}_ino_{token}"토큰에 들어가는 값은 정확한 장비 ID여야 합니다. 장비명을 넣으면 등록은 되지만 실행 시점에 대상을 찾지 못합니다.
감시 자동화 등록
폴더를 감시해 파일이 들어오면 바로 전송하기
실시간 감시는 transferType을 sync로 두고 transferOptions에 syncType을 넣습니다.
import time
def now_iso():
return time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
def create_watch(source, source_path, target, target_path,
watch_type=1, action="overwrite", webhook=None):
body = {
"name": f"watch {source_path}",
"flowName": f"watch {source_path}",
"transferType": "sync",
"timezone": "Asia/Seoul",
"step": 1,
"isUpcoming": False,
"details": [
{
"senderId": source,
"receiverId": target,
"sourceItem": [
{
"hash": encode_path(source, source_path),
"filePath": source_path,
"isDir": True,
}
],
"targetPath": encode_path(target, target_path),
"step": 1,
"transferOptions": {
"noSchedule": True,
"target-action": action,
"send-fileoption": {},
"syncType": 1,
"watchFolderType": watch_type,
},
}
],
"schedules": [
{"type": "none", "startDateType": "now",
"startDate": now_iso(), "timezone": "Asia/Seoul"}
],
}
if webhook:
body["processors"] = [{
"category": "run",
"type": "http",
"config": {"url": webhook, "method": "POST"},
}]
return api("POST", "/api/automations", body)["automationId"]자동화 요청에서 반드시 지켜야 하는 항목이 네 개 있습니다.
| 항목 | 지정 방식 |
|---|---|
isUpcoming | 반드시 false. 서버 기본값 true는 요청에 담긴 일정을 무시하고 5분짜리 일회성 일정으로 대체합니다. triggerAutomation이 붙은 단계는 서버가 false로 강제하므로, 트리거가 없는 첫 단계에만 직접 지정하면 됩니다 |
step | 최상위와 details 양쪽에 넣습니다. 흐름 안에서의 홉 위치입니다 |
sourceItem | hash(경로 토큰)와 filePath(평문 경로)를 함께 넣습니다 |
syncType | transferOptions 안에 넣습니다. 1은 단방향, 2는 양방향입니다 |
네 항목 모두 누락해도 등록은 성공하고 실행 시점에 동작이 달라집니다. 반복 일정을 등록했는데 한 번만 실행되고 끝났다면 isUpcoming부터 확인합니다.
서버는 감시 경로를 sourceItem[0].filePath에서 읽습니다. 경로 토큰만 지정하고 평문 경로를 생략하면 감시 대상이 설정되지 않습니다.
watchFolderType | 감지 대상 |
|---|---|
1 | 파일 생성 (기본값) |
2 | 파일 변경 |
값은 문자열이 아니라 정수입니다.
감시는 파일이 들어올 때마다 실행됩니다. 도착 정책을 numbering으로 두면 대상 폴더가 빠르게 불어나므로, 최신 상태만 유지하면 되는 구성에서는 overwrite를 씁니다.
에이전트는 파일 크기 변화가 멈추면 쓰기 완료로 판단하고 이벤트를 전달합니다. 큰 파일일수록 감지에서 이벤트까지 시간이 더 걸리는데, 잘린 파일이 전송되지 않게 하기 위한 동작입니다.
create_watch에 webhook을 넘기면 자동화 본문의 processors에 아래 형태로 등록됩니다.
{
"processors": [
{
"category": "run",
"type": "http",
"config": {
"url": "https://internal.example.com/hook",
"method": "POST",
"body": { "event": "transfer_done" }
}
}
]
}
category는 run, type은 https가 아니라 http입니다. url·method·body는 config 안에 넣습니다. 호출 시점은 전송 완료 후이며, config.events에 {"completed": true}를 지정하면 성공한 전송에만 호출됩니다. 생략하면 실패를 포함한 모든 이벤트에 호출됩니다.
감시 자동화 관리
등록된 감시 자동화 조회하고 정리하기
감시 자동화도 일반 자동화와 같은 목록에 나타납니다. transferType이 sync인 항목이 실시간 감시입니다.
items, _ = list_automations(search="watch")
for item in items:
print(item["automationId"], item.get("automationName"),
item.get("transferType"))
# Delete an automation you no longer want to watch
api("DELETE", f"/api/automations/{automation_id}")자동화 목록은 흐름 그룹으로 중첩되어 반환되므로 안쪽 배열까지 순회해야 합니다. 항목의 이름은 automationName이 아니라 생성 시 넘긴 flowName에 저장됩니다.
후속 시스템 호출
프로세서가 호출한 URL을 받아 후속 작업 시작하기
지정한 URL의 엔드포인트는 그 요청을 다음과 같이 처리합니다.
호출은 전송 완료 후에 오지만, config.events를 생략하면 실패한 전송에도 옵니다. 실패에 반응하려면 받는 쪽에서 상태를 확인해 성공과 실패를 나눕니다.
def handle_notification(payload):
monitor_id = payload.get("monitorId")
# If you subscribed to the completed event only, this check can be skipped
if monitor_id:
detail = api("GET", f"/api/transfers/{monitor_id}")
if detail["status"] != STATUS_COMPLETE:
return handle_failure(payload)
start_downstream_job(payload)같은 전송에 대해 알림이 여러 번 올 수 있으므로, 받는 쪽은 같은 이벤트를 여러 번 받아도 한 번만 처리되도록 만듭니다.
실행 결과 확인
이벤트로 시작된 작업의 결과 조회하기
runs = api("GET", f"/api/automations/{automation_id}/executions") or []
for run in runs:
print(run["startTime"], run["status"], run["monitorId"])실행 이력은 최신 회차가 배열 앞에 오며 페이징 없이 전체가 반환됩니다. 각 회차의 monitorId로 파일별 처리 결과까지 확인할 수 있습니다.
누락 복구
소스와 대상 목록을 비교해 누락된 파일만 재전송하기
장비가 잠시 오프라인이었거나 감시가 중단된 사이에 들어온 파일은 감지되지 않습니다.
def list_files(device_id, path):
found, page = {}, 1
while True:
result = api("GET", f"/api/devices/{device_id}/files", params={
"path": path, "page": page, "size": 200, "type": "file",
})
for item in result["items"]:
found[item["name"]] = item.get("size")
if page >= result.get("lastPage", 1):
return found
page += 1
def recover_missing(source, source_path, target, target_path):
source_files = list_files(source, source_path)
missing = sorted(set(source_files) - set(list_files(target, target_path)))
if not missing:
return None
# send file lists through sourceItem; sourcePaths treats every path as a folder
return api("POST", "/api/transfers/manual", {
"sourceDevice": source,
"targetDevice": target,
"targetPath": target_path,
"sourceItem": [
{"path": f"{source_path.rstrip('/')}/{name}",
"isDir": False,
"fileSize": source_files[name]}
for name in missing
],
"sendAllFolder": False,
"transferOptions": {"target-action": "overwrite"},
})["monitorId"]파일 크기를 함께 넘기면 서버가 항목별 크기를 다시 조회하지 않아 빨라집니다.
실시간성이 중요해 감시를 쓰는 것이므로, 점검은 하루 한 번 주기로 실행해 누락을 보완하는 용도로 사용합니다.
| 점검 항목 | 확인 내용 |
|---|---|
| 감시 자동화 | transferType과 syncType, watchFolderType |
| 감시 경로 | sourceItem[0].filePath 지정 여부 |
| 일정 교체 | isUpcoming: false 여부 |
| 실행 이력 | 회차별 처리 결과 |
| 누락 파일 | 소스에 있으나 대상에 없는 파일 |