본문으로 건너뛰기
Paul's Dev Notes

Flow Designer 는 언제·어떻게 실행되고 어디서 멈추나 — 실행 라이프사이클과 에러 처리 메커니즘

record-triggered flow 가 트랜잭션 'after engines' 단계에서 발화하는 실행 순서, background 기본 vs foreground opt-in 선택, 에러 시 stop-on-error·Try·Flow error handler·For Each 분기, sys_flow_context 와 com.snc.process_flow.reporting.level 로 조용한 실패를 진단하는 법. 빌딩블록 선택·튜토리얼 구현은 앞선 글에 위임하고 '고른 것이 어떻게 실행/실패하나'만 다룬다.

· note flow-designer scripting
검증 인스턴스: OOTB Australia · 검증일 2026-07-12

개요

흔한 오해 두 가지를 먼저 정리한다.

오해 (1) — “flow 는 저장하자마자 돈다”

아니다. record-triggered flow 는 save 커밋 후 별도 worker thread 에서 비동기로 실행된다.

오해 (2) — “flow 의 Update Record 가 Business Rule 과 함께·또는 먼저 돈다”

아니다. record-triggered flow 는 트랜잭션 시퀀스의 after engines 단계에 앉는다. before-BR(Business Rule, 비즈니스 규칙)과 절대 interleave 되지 않는다. “flow 가 먼저 값을 세팅하겠지”라는 가정은 여기서 깨진다.

Flow Designer Action vs SubFlow vs Script 는 빌딩블록 선택을, Incident 자동 라우팅 글은 flow 구성 실습을 다뤘다. 이 글은 “그렇게 짠 flow 가 런타임에 언제·어떻게 실행/실패하는가”를 판다 — 발화 시점, background/foreground 선택, 에러 경로, 실행 상태 진단까지.

OOTB(Out-of-the-Box, 기본 제공) Australia 릴리스 기준입니다. 실행 순서·에러 처리·sys_flow_context 메커니즘은 릴리스 전반에 일관되지만, UI 명칭(Xanadu 이후 Flow Designer 는 Workflow Studio 로 통합됨)과 일부 속성 라벨·기본값은 인스턴스 버전·릴리스에 따라 다를 수 있으니 대상 인스턴스에서 확인을 권장합니다.


1. flow 는 트랜잭션의 어느 지점에서 발화하나 — “BR 이 끝난 뒤, after engines 에서”

레코드 저장 시 스크립트·엔진 실행 순서는 공식 문서 기준 8단계로 구성된다. record-triggered flow 는 이 중 ‘after engines’ 단계에 앉는다 — DB 연산과 order 1000 미만 after-BR 이 끝난 뒤, 알림과 order 1000 이상 after-BR 보다 앞이다.

① before-BR + before enginesDB 쓰기 전 값 검증·변환 단계② DB 연산 + after-BR (order < 1000)레코드 커밋 후 after-BR 초기 실행③ after engines — Trigger engine★ record-triggered flow 발화이후: 알림 + after-BR (order ≥ 1000)

이 시퀀스에서 핵심은 두 가지다. 첫째, 발화 시점과 action 실행 시점은 다르다 — after engines 에서 Trigger engine 이 flow trigger 를 큐에 넣고, action 은 별도 background thread 에서 비동기로 이어진다. 둘째, before-BR 은 이미 끝난 단계이므로 record-triggered flow 와 interleave 되지 않는다.

BR 의 when×on×order 매트릭스와 setWorkflow(false) 세부 목록은 Business Rule 무한 루프 진단이 정본이다.


2. background 가 기본, foreground 는 opt-in — “save 를 블록하느냐”

record-triggered flow 의 ‘Where to run the flow’ 기본값은 ‘Run flow in background (default)’ 다. 비동기이며, save 트랜잭션을 블록하지 않는다. 사용자는 폼 저장 즉시 응답을 받고, flow 는 worker thread 에서 별개로 실행된다.

Background (기본)

  • 비동기 — save 무블록, 사용자 대기 없음
  • 커밋 뒤 worker thread 에서 실행
  • flow priority(기본 medium)로 큐잉
  • 대량 업데이트·import 시 지연이 발생하는 경우가 많다
  • REST·통합·루프 등 긴 작업에 적합

Foreground (opt-in)

  • 동기 — 세션 thread 를 블록, 사용자 대기
  • 트리거 레코드 현재 런타임 데이터 즉시 접근 가능
  • 즉각 피드백·현재 데이터 접근이 필요한 짧은 작업 한정
  • 오래 걸리는 통합·루프는 background/비동기 subflow 로 offload 권장

background flow 가 “왜 즉시 안 도나/왜 방금 바뀐 값을 못 읽나”의 근본 원인이다. 트리거~실행 사이에 다른 자동화가 값을 바꾸면 flow 는 이전 값을 읽는 경우가 있다.

스크립트에서 직접 호출할 때는 FlowAPI 를 사용한다. sn_fd.FlowAPI.getRunner().flow('scope/name').inBackground().run(inputs) 가 기본(비동기)이고, .inForeground().run(inputs) 로 동기 실행하면 출력을 즉시 읽을 수 있다. 동기 실행 시간 제한은 §4 에서 다룬다.


3. 에러가 나면 flow 는 기본적으로 멈춘다 — stop-on-error 와 탈출구

main section 에서 action 또는 subflow 가 에러를 반환하면, 기본 동작은 flow 정지 다. 이후 스텝은 취소된다. 이것이 기본이지만, 에러가 surface 되는 방식과 flow 설계에 따라 결말이 달라진다.

action 에러는 surface 여부와 flow 설계에 따라 네 갈래로 나뉜다.

정지

기본 — flow 정지

에러가 error 로 surface 되면 flow 가 멈추고 이후 스텝이 취소된다.

계속

Try 로 감쌈 — caught

catch 브랜치 실행 후 나머지 flow 는 정상 진행된다(‘Completed (Error caught)’). Flow error handler 는 트리거되지 않는다.

핸들러 실행

Flow error handler 켜짐

main 나머지를 취소하고 handler 섹션(알림·로깅·remediation subflow)을 실행한다.

정지

For Each 내부 — 루프 전체 정지

한 반복의 에러가 루프 전체와 flow 를 멈춘다. 다음 아이템으로 넘어가지 않는다.

조용한 실패의 원리: action 의 Error Evaluation 설정에서 실패가 error 로 surface 되지 않으면, flow 는 멈추지 않고 계속 진행해 ‘Completed (Error Skipped)’ 로 끝나는 경우가 있다. Error Evaluation 구성을 확인하지 않고 ‘flow 가 Completed 됐으니 성공’이라고 보면 함정이다.

Try 로직: 감싼 스텝에서 에러가 나면 catch 브랜치가 실행되고 나머지 flow 는 정상 진행된다. Try 가 잡은 에러는 Flow error handler 를 트리거하지 않는다(‘Completed (Error caught)’). Try 는 1회만 쓸 수 있다.

Flow error handler: 캔버스 하단 토글로 켠다. main 의 어느 스텝에서든 에러가 나면 나머지 main 을 취소하고 handler 섹션을 실행한다(알림·로깅·remediation subflow 등). 섹션 아이템 수 상한은 인스턴스에서 확인을 권장한다.

For Each 함정: 한 반복에서 에러가 나면 루프 전체와 flow 가 정지한다. 다음 아이템으로 이어가지 않는다. per-item 격리는 반복부를 error handler 를 켠 subflow 로 분리하거나 Try 로 감싸는 것이 권장 패턴이다.

에러가 난 triggered flow 는 자동으로 재시작되지 않는 경우가 일반적이다. 재트리거 필요 여부는 인스턴스 구성에 따라 직접 확인을 권장한다.


4. retry·wait·timeout — 오래 걸리는 flow 의 실행 경계

메커니즘적용 대상기본값 / 임계주의
Retry PolicyJDBC·REST·SOAP 통합 스텝 전용IntegrationHub > Retry Policy 관리core action(Create/Update Record 등)에는 자동 retry 없음
Wait for Condition선택한 레코드 필드 변경 시 재평가update-driven(폴링 아님)dot-walk·관련 레코드·catalog 변수 변경은 감지 불가; 모니터 필드를 건드리지 않으면 wait 가 안 풀림
동기 FlowAPI 실행inForeground().run()com.glide.hub.flow_api.default_execution_time 기본 30000ms(30초), 최대 REST 트랜잭션 쿼터(기본 60초)로 캡긴 대기는 inBackground() + 상태 확인으로 offload
Presumed Interrupted모든 장기 실행 context현재 노드 15분 초과 & 유효 트랜잭션 ID 상실, 또는 다른 노드 8시간 초과상태 변경 후 sys_flow_context 에 영속

Retry Policy 오해 교정: core action 에는 자동 retry 가 없다. Retry Policy 는 IntegrationHub 구독이 전제인 통합 스텝 전용이다.

Wait for Condition 함정: 폴링이 아니라 지정 레코드 필드가 업데이트될 때만 재평가한다. dot-walk 경로나 catalog 변수 변경은 감지하지 못한다. 안전한 패턴은 sys_id 직접 참조 + Look Up Record 조합이다.


5. 실행 상태를 어떻게 읽나 — sys_flow_context 와 reporting.level

flow 실행은 sys_flow_context 테이블(dictionary label ‘Flow engine contexts’)에 저장된다. Source Record 필드가 트리거 레코드와 연결된다.

진단 경로: sys_flow_context.list → Source Record 를 트리거 레코드 sys_id 로 필터(reference 필드이므로 sys_id 로만 가능) → Status·Error 메시지 확인.

핵심 함정 — reporting.level 이 OFF 이면 아무것도 보이지 않는다

Rome 릴리스 이후 flow reporting/debugging 이 기본 off 인 인스턴스(특히 prod)가 많다. com.snc.process_flow.reporting.level 시스템 속성이 이를 제어하며, off 상태면 execution view 에 ‘Flow reports not available. Check system property com.snc.process_flow.reporting.level’ 에러가 뜨거나 sys_flow_context 가 비어 보인다. “조용한 실패처럼 보이는” 현상의 상당 부분이 에러 처리 미구성 + reporting off 이중 사각 때문이다.

레벨 조정은 Process Automation > Properties 에서 전역 상향(Flows Only / Flows and Actions / Flows Actions and Steps / Developer Trace)하거나, flow 캔버스 ’…’ > Flow reporting settings 로 per-flow 설정을 올린다. prod 에서는 영향 범위를 고려해 per-flow 를 먼저 시도하는 편이 안전한 경우가 많다.

sys_flow_log(sys_flow_log.list) 에서 ‘Log’ action 출력을 별도 확인할 수 있는 경우도 있으나, reporting.level 연동 여부는 인스턴스에서 직접 확인을 권장한다. 테스트 실행은 실제 레코드를 건드릴 수 있으므로 sub-prod 환경이 안전하다.


6. 흔한 오해·오설계 — 런타임 관점

오해 1

flow 가 방금 바뀐 값을 읽겠지

background flow 는 커밋 후 worker thread 에서 실행된다. 트리거~실행 사이에 다른 자동화가 값을 바꾸면 낡거나 덮인 값을 읽는 경우가 있다. 현재 데이터가 필요하면 foreground 또는 조건 재확인 패턴 검토(§2 참고).

오해 2

Update Record 는 자동으로 안전 — 재트리거·루프 무관

BR 이 레코드를 업데이트하면 flow 트리거 조건이 재충족되고, flow 가 다시 Update Record 하면 BR 이 재발동하는 루프가 만들어진다. 완화는 플래그 확인 + 미설정 시만 트리거. BR 무한 루프 진단 참고.

오해 3

action 실패하면 flow 가 알려주겠지

Error Evaluation 설정에서 error 로 surface 되지 않으면 flow 는 ‘Completed (Error Skipped)’ 로 조용히 끝난다. reporting.level 이 off 까지 겹치면 이중 사각이 된다(§3·§5 참고).

오해 4

For Each 가 나머지 아이템은 계속 돌겠지

한 반복에서 에러가 나면 루프 전체와 flow 가 정지한다. native ‘continue on error’ 토글은 없다. per-item 격리가 필요하면 반복부를 error handler 를 켠 subflow 로 분리하거나 Try 로 감싸야 한다(§3 참고).

오해 5

flow 가 state 를 바꾸려다 ITSM BR 에 막혀 실패

Incident state 를 In Progress 로 전환할 때 assigned_to 가 없거나 전이 규칙에 걸리면 OOTB BR 이 abort 를 던져 flow 가 에러로 종료된다. state 값·전이 규칙은 ITSM Incident state 모델로 위임한다.


마무리

이 글로 Flow Designer 시리즈의 세 번째 축이 완성됩니다. 빌딩블록 선택(Action vs SubFlow vs Script), flow 구성 실습(Incident 자동 라우팅), 그리고 이 글이 다룬 “런타임에 언제·어떻게 실행/실패하는가”까지 — 세 축이 맞물려야 Flow Designer 로 안정적인 자동화를 짤 수 있습니다.

BR 의 실행 순서·재트리거 함정을 Flow Designer 로 옮겨와도 문제의 씨앗은 남습니다. 가시성(실행 로그·error handler)은 BR 보다 낫지만, background 지연과 조용한 실패가 새 함정입니다. BR 쪽 재트리거·루프 문제는 Business Rule 무한 루프 진단을 함께 읽으면 비교 관점이 생깁니다.

다음으로 어떤 방향이 궁금하신가요? IntegrationHub REST 통합 flow 의 에러/재시도 심화, 또는 환경 간 이관 전략 등 실무 밀착 주제를 이어갈 수 있습니다.