Flow 하나 실행하기
용도
client.run(...)은 client = px.Client(...)로 만든 Client 객체의 메서드입니다. Flow Run 하나를 시작하며, Report가 필요 없으면 Flow와 input을 직접 전달합니다. Report 결과 위치까지 연결했다면 저장한 Report–Flow connection을 전달합니다.
저장된 FlowRef 실행
client.save(flow)나 client.apply_flow_change(plan, command_id=...)가 반환한 FlowRef도 직접 실행할 수 있습니다. 입력 선언은 해당 revision에서 읽고 Core codec과 digest를 검증합니다. 원래 Flow 작성 객체나 Function 소스를 다시 등록하지 않으며 현재 head로 바꾸지 않습니다.
saved = client.save(flow)
run = client.run(saved, width=10.0, depth=20.0,
run_key="section_a", command_id="section_a_submit")
run = run.wait(timeout_seconds=120)입력 이름과 값은 그 Flow의 선언에 맞춰 지정합니다. 작성한 Flow를 실행할 때와 같은 정수·Decimal·날짜/시간·기간·목록 변환과 단위를 사용합니다. 누락·미선언·잘못된 입력은 기존 Core 실행 검증을 따릅니다. 다른 Project의 참조는 읽거나 제출하지 않습니다.
FlowRef 주소는 saved.to_dict()로 보관하고 다음처럼 복원할 수 있습니다.
from pipelinexlab import px
saved = px.FlowRef(flow_key=address["flowKey"], revision_ref=address["revisionRef"],
workspace=address["workspaceKey"], project=address["projectKey"])
with px.Client(workspace=saved.workspace, project=saved.project) as client:
run = client.run(saved, width=10.0, depth=20.0,
run_key="section_a", command_id="section_a_submit")원래 입력과 두 ID를 함께 보관해야 같은 Run을 재조회할 수 있습니다. 같은 ID에 다른 revision이나 입력을 지정하면 기존 재시도 계약에 따라 거절합니다. 실행하지 않은 revision은 과거 head여도 정확한 주소로 실행할 수 있습니다. FlowRef 직접 실행은 Report에 자동 반영하지 않습니다.
화면에서 보이는 것
Flow를 직접 전달하는 방식은 PXFLOW Studio의 Run에 대응합니다. Report connection 실행은 저장된 Report의 입력과 결과 연결을 사용하는 동작입니다. Report 실행 서비스가 연결된 환경에서는 Report Workbench 상단 Run → Connection 선택 → Run connection으로 실행합니다. 미저장 변경이 있으면 먼저 저장하고, 저장 실패·충돌이 있으면 실행하지 않습니다.
실행 패널은 같은 Run의 수치·표·PNG 원본을 읽으며 계산 상태와 Report 반영 상태를 따로 표시합니다. 접수 응답이 끊기면 패널의 같은 요청 재시도를 사용합니다. 패널을 닫았다 다시 열어도 현재 세션의 실행 요청은 유지되지만, 브라우저 종료 뒤 미확정 요청의 자동 복구는 아직 지원하지 않습니다.
반영 완료 후 **Open applied Report(반영된 Report 열기)**를 선택하면 그 Run이 반영한 정확한 저장본을 엽니다. 미저장 초안은 먼저 저장하거나 되돌려야 합니다. 읽는 도중 새로 편집하거나 저장했다면 현재 본문을 유지하며, 읽기 실패 때도 초안을 교체하지 않습니다. 선택한 Run은 유지됩니다. 반영된 리비전 이후에 다른 저장본이 생겼더라도 자동으로 최신 head를 열지 않습니다. Flow 주소와 조회 서비스가 연결된 환경에서는 이 Run을 Flow에서 열기로 새 탭의 Results에서 같은 실행을 확인할 수 있습니다. 현재 Report 초안은 유지되며 새 계산이나 결과 복사를 만들지 않습니다. 실행 당시 Flow 리비전을 열고, 결과는 Run을 소유한 Project에서 조회합니다. Flow 정의와 Run의 Project가 다르면 이 보기에서는 새 계산을 제출할 수 없습니다. 새 계산은 Flow의 기본 주소에서 시작합니다. 주소나 조회 서비스를 사용할 수 없으면 이유를 안내합니다.
실행 서비스가 없는 환경에서는 실행을 사용할 수 없으며 아래 SDK 예제를 사용합니다. 이 연결 설명은 모든 배포에 서비스가 제공된다는 뜻이 아닙니다.
문법
client.run(flow, **inputs)
client.run(connection, run_key=None, command_id=None)Flow를 직접 실행하는 예제
from pipelinexlab import px
from project_flows.girder_check import flow
client = px.Client(workspace="engineering", project="bridge_project")
run = client.run(flow, span=12.0, demand=860.0)Report connection을 실행하는 예제
아래 strength는 report.connect_flow(...)으로 만들고 report.save()로 저장한 connection입니다.
run = client.run(strength)서버에서 확인하는 권한
server-local HTTP composition은 Report connection 제출 때 Report가 속한 Project의 run.execute와 artifact.read를 확인합니다. 저장된 connection에 결과 반영 mapping이 있으면 artifact.write도 필요합니다. 반영 mapping이 없는 실행에는 Report 쓰기 권한을 요구하지 않습니다.
참조 Flow가 다른 Project에 있으면 그 Project의 읽기·실행 권한도 별도로 확인합니다. Run은 Report가 속한 Project에서 조회합니다. Worker는 제출 시 고정한 Flow의 Project와 revision에서 정의를 읽습니다. 다른 Project 참조의 단일 실행·Report 반영과 서버 재시작 복구는 현재 소스의 SDK/서버 경계에서 검증했으며, 정식 웹 계정/BFF 연결과 공개 서비스 배포는 별도입니다.
서버 운영자가 고정 Python 환경을 지정하면 접수한 Run은 그 환경의 lock을 저장하고, Worker도 같은 환경에서 실행합니다. 요청 JSON으로 서버의 Python 경로를 선택할 수 없습니다. 서버의 실행 환경 설정과 공개 SDK의 로컬 Client 접속 방식은 별개입니다.
report.connect_flow(key, flow)에 작성 중인 px.Flow를 전달하면 Report Client의 Project에 그 Flow를 저장합니다. 다른 Client에서 먼저 Flow를 저장한 것만으로 외부 참조가 되지는 않습니다. 외부 Flow의 정확한 주소가 이미 저장된 Report는 기존 내보내기·가져오기로 그 참조를 유지할 수 있으며, client.open_report(...).connection(...)으로 열어 실행합니다.
계산 성공과 Report 반영 완료는 구분합니다. run.refresh().projection으로 반영 상태를 확인합니다. 서버는 계산이 성공한 미반영 Run을 재시작 후 다시 처리하며, 이미 저장한 반영 영수증이 있으면 그 revision을 복구합니다. 이 과정에서 계산을 다시 제출하지 않습니다. 일부 결과가 계속 반영 대기 중이어도 다른 Run을 차례로 처리하며, 대기 중인 결과도 다시 확인합니다. 단일 connection 실행의 반영 대상 기록이 누락된 경우에도 검증된 반영 영수증이 있으면 원래 revision을 복구합니다. 영수증도 없어 반영 대상을 확인할 수 없으면 reportProjectionSuperseded로 거절하며, Run의 계산 결과는 보존합니다.
같은 요청을 재시도할 때도 권한을 다시 확인합니다. 거절은 PX_PERMISSION_DENIED 진단의 params.requiredPermission으로 부족한 권한을 구분합니다. credential에 연산 이름이 있거나 Project 목록이 보이는 것만으로 실행이 허용되지 않습니다. 이 설명은 서버 제출 경계에 대한 것이며, SDK 호출 문법·저장 파일 형식·로컬 Client의 사용법은 바뀌지 않습니다.
매개변수
| 이름 | 설명 |
|---|---|
flow | 실행할 px.Flow 객체 또는 정확한 저장 revision을 지정하는 FlowRef |
inputs | span=12.0처럼 Flow input key와 값으로 작성한 직접 실행 input |
connection | report.connect_flow(...)이 반환하고 Report에 저장한 connection |
run_key, command_id | 재시도할 때 함께 전달하는 원래 식별자. 모두 생략하면 새 실행 |
반환
시작한 Flow Run을 추적하는 Run 객체를 반환합니다. run.key, run.state, run.done을 읽고, run.refresh()/run.wait()/run.cancel()은 그 시점 상태의 새 Run을 반환하며 (들고 있는 객체는 불변), run.result()는 이름 붙은 Result 참조(ResultSnapshot)를, run.to_dict()는 wire 그대로를 반환합니다. 거부는 diagnostics에 구조화된 Diagnostic(code, path, params)로 담깁니다.
Run은 실행 응답으로만 만들어지는 output-only 값이므로 px.Run(...)으로 직접 생성할 수 없습니다. lifecycle 메서드(refresh, wait, cancel, result)는 Run을 만든 원래 Client를 빌려 쓰므로 그 Client가 열려 있어야 합니다. key, state, done, to_dict() 같은 snapshot 읽기는 Client 호출을 하지 않습니다.
실행 실패 원인은 run.refresh().diagnostics에서 확인합니다. 이는 요청 자체가 거절되어 발생하는 exception과 별개입니다. 함수·Component body 실패는 각각 PX_FUNCTION_FAILED, PX_COMPONENT_FAILED이며, 원문 예외를 파싱하지 않고 code·path·params를 사용합니다.
completed = run.wait().refresh()
for diagnostic in completed.diagnostics:
print(diagnostic.code, diagnostic.path, diagnostic.params)진단은 불변 tuple입니다. 성공하거나 기존 Runtime이 진단을 제공하지 않으면 비어 있습니다. run.to_dict()의 기존 실행 레코드는 바뀌지 않으며 진단은 [item.to_dict() for item in run.diagnostics]로 별도 직렬화합니다.
저장된 Run과 실행 당시 입력 읽기
import json
from pipelinexlab import px
with px.Client(workspace="engineering", project="bridge_project") as client:
run = client.get_run("analysis_1")
submitted = json.loads(run.read_inputs(max_bytes=1024 * 1024))
# submitted["span"] = {"type": {"kind": "float64"}, "unit": "m", "value": 12}get_run(run_key)는 지정한 Project에 이미 저장된 Run만 조회합니다. Flow 작성 객체·원래 입력· command ID를 다시 제출할 필요가 없고 재계산하지 않습니다. 없는 Run은 px.Error의 PX_TARGET_NOT_FOUND로 거절합니다. 조회한 Run의 lifecycle은 현재 Client에 연결됩니다.
실행에 사용한 Flow 위치
client.get_run(key).flow_ref와 run.refresh().flow_ref는 저장소가 기록한 원본 Flow의 px.FlowRef를 반환합니다. workspace, project, flow_key, revision_ref로 실행 당시의 정확한 정의를 확인할 수 있습니다. Report connection 실행에서는 Run의 Project와 다를 수 있으며, 이 참조만으로 원본 Flow의 읽기·실행 권한이 생기지는 않습니다.
run = client.get_run("analysis_1")
source = run.flow_ref
if source is not None:
print(source.workspace, source.project, source.flow_key, source.revision_ref)출처를 제공하지 않는 이전 Runtime 응답이나 제출 응답에서는 None입니다. Client의 현재 Project나 최신 Flow 리비전으로 추정하지 않습니다. 출처는 불변 값이며 run.to_dict()는 기존 Run 레코드만 반환합니다. 출처를 별도로 직렬화하려면 source.to_dict()를 사용합니다.
실행 당시 입력
read_inputs는 저장된 실행 당시 입력을 canonical JSON bytes로 반환합니다. 각 입력은 type, 선택적 unit, value를 포함하며 int64·Decimal 등은 wire 문자열을 유지합니다. 화면의 미저장 입력이나 현재 Flow revision에서 재구성하지 않습니다. 실행 전과 실패한 Run도 저장된 입력을 조회할 수 있으며, 과거 입력 파일이 없으면 현재 값으로 채우지 않고 거절합니다.
max_bytes는 0–64 MiB의 전체 반환 상한입니다. 64 KiB씩 읽으며 Run·Flow revision·입력 digest와 최종 bytes digest를 검증합니다. Project에 없는 Run은 PX_TARGET_NOT_FOUND, 크기 초과는 PX_RESOURCE_LIMIT, 누락·손상된 내용은 PX_SOURCE_UNREADABLE로 확인합니다. 신규 product operation을 포함한 SDK/Runtime descriptor가 일치해야 합니다. 기존 Run record와 입력 저장 형식은 바뀌지 않습니다. 이 조회만으로 화면 초안과의 일치 여부를 판정하지는 않습니다.
결과 내용 읽기
import json
completed = run.wait()
value = json.loads(completed.read_result("answer", max_bytes=1024 * 1024))read_result(name: str, *, max_bytes: int) -> bytes는 같은 Run에 저장된 named result를 읽습니다. 일반 결과는 canonical JSON bytes이며 int64·decimal 등은 canonical 문자열 표현을 유지합니다. Runtime에 생성 파일로 확정된 artifact/binary 결과는 원본 bytes입니다. 파일 생산은 px.Artifact.from_bytes를 사용합니다. 실제 라이브러리 환경과 그림 생성 사례의 검증 완료 여부는 별도로 확인합니다.
max_bytes는 전체 반환 내용의 상한으로 0–64 MiB를 지정합니다. 한 프레임은 최대 64 KiB이며, SDK는 전체 길이·snapshot·content digest를 확인한 뒤 bytes를 반환합니다. 조회는 재계산하지 않고 Run을 만든 Client가 열려 있어야 합니다. 같은 요청을 새 Client로 재제출해 기존 Run을 얻은 경우에도 그 Client가 가진 Run으로 다시 읽을 수 있습니다.
누락된 Run/결과는 PX_TARGET_NOT_FOUND, 반환량 초과는 PX_RESOURCE_LIMIT, 내용 누락/변조는 PX_SOURCE_UNREADABLE로 거절합니다. 이전 digest-only artifact는 생성 파일 metadata가 없으므로 PX_DOCUMENT_MALFORMED로 거절하며 임의 CAS 파일로 따라가지 않습니다. 다른 snapshot으로 바뀐 후속 프레임은 PX_RUN_STATE_CONFLICT로 거절합니다. 모두 px.Error.diagnostics로 확인합니다.
서버와 SDK의 product-operation schema가 일치해야 합니다. 기존 Run.result()와 fixed Tool catalog는 그대로 유지됩니다. SDK 반환량·전송량 제한은 서버의 전체 메모리 사용량 보장과 다릅니다. SQLite/PostgreSQL 파일 저장소는 같은 조회용 snapshot reader를 사용합니다. 새 조회는 원본 전체의 digest를 검증하고, 이어지는 chunk는 검증한 복사본에서 읽습니다. 저장소 인스턴스와 clone이 공유하는 snapshot 버퍼는 검증 중 할당을 포함해 64 MiB·최대 16개이며 큰 파일은 임시 디스크로 복사합니다. 64 KiB 복사 버퍼와 응답 chunk, SDK가 조립하는 결과는 별도입니다. 완료·교체·퇴출·마지막 owner 종료 시 임시 복사본을 해제하고, 각 chunk에서 저장소 접근 권한을 다시 확인합니다. 첫 검증의 전체 파일 읽기 비용과 임시 디스크 용량은 남으므로 서버 전체 RSS나 디스크 상한을 max_bytes와 같다고 해석하지 않습니다.
규칙
- Flow 또는 connection 하나는 Flow Run 하나를 만듭니다.
- Run lifecycle을 더 사용하려면 원래
px.Client를 닫지 않습니다. 다른 Client나 implicit fallback으로 Run의 Project를 다시 선택하지 않습니다. - 직접 실행할 때는 Flow revision과 전달한 input을 고정합니다.
- connection 실행 시 Report revision, 저장된 input 연결·결과 위치, Flow revision과 input을 고정합니다.
- 한 connection의 여러 input 연결은 같은 Run에 함께 들어갑니다.
- connection 실행은 result mapping의 projection intent를 함께 기록하고, Run이 성공하면 Runtime이 그 스냅샷을 새 Report revision으로 투영합니다(2026-09-02부터 production worker 경로). 현재 Python facade가 materialize하는 input mapping은 exact saved Report revision의 scalar
reportValue이며, Table·attachment source와 composite value가 있는 connection은 제출 전에 이름 있는 refusal로 중단합니다. list[T]또는px.Table[RecordType]input은 collection 전체를 받는 Run 하나로 실행됩니다.- 새 실행 의도는 새 Run을 만들고 이전 Run과 Result는 이력에 보존됩니다.
응답 유실과 재시도
Flow와 Report connection 모두 run_key·command_id를 함께 지정할 수 있습니다. 같은 고정 revision·입력·식별자를 다시 제출하면 Runtime은 기존 Run을 돌려줍니다. 새로운 실행 의도에는 새 식별자를 사용합니다.
run = client.run(strength, run_key="review_run_01", command_id="review_submit_01")제출 중 px.Error가 발생하면 error.run_key, error.command_id로 식별자를 확인합니다. error.outcome_unknown이 참이면 응답이 확정되지 않았다는 뜻이지, 실행이 취소됐다는 뜻이 아닙니다. 연결이 종료됐다면 원래 connection 객체를 보관한 상태에서 같은 Project의 새 Client로 같은 식별자를 전달합니다. Report를 다시 저장하거나 최신 revision으로 바꾸지 않습니다. 현재는 호출자 프로세스가 종료된 뒤 저장된 connection을 실행 핸들로 다시 여는 공개 API가 없습니다. 식별자만 파일에 보관하면 자동 복구된다고 가정하지 마세요. SDK는 재시도 파일 생성·재제출을 자동으로 하지 않습니다. 이 규칙이 외부 부수 효과의 정확히 한 번 실행까지 보장하는 것은 아닙니다.
Client(timeout=...)은 연결 수립 및 각 요청 전체 교환의 대기 예산입니다. 응답 chunk가 조금씩 도착해도 요청 deadline은 연장되지 않습니다. 실행 자체의 제한 시간은 Function 실행 policy를 따르며, 실행 취소는 접수된 Run에 대한 run.cancel()이라는 별도 동작입니다. 전체 deadline은 Unix socket에서 검증했습니다. Windows named pipe는 읽기 polling에 남은 시간을 전달하지만 현재 blocking 연결 수립·쓰기에는 강제 deadline이 구현되어 있지 않습니다.
다음 단계
생성 파일은 Function/Component의 px.Artifact.from_bytes 반환에서 시작합니다. 원본 bytes는 이 Run의 read_result로 읽으며 조회가 계산을 다시 실행하지 않습니다.