외부 프로그램에서 스트림으로 데이터 보내기
Push 기반 수집은 외부 프로그램이 이벤트 발생 시 Foundry API를 호출하여 스트림에 레코드를 쓰는 방식입니다. Foundry가 원천을 조회하는 일반 동기화와 연결 시작 방향이 다릅니다. 이미 소스가 있다면 스트리밍 동기화를 사용할 수 있고, 외부 서비스가 Foundry 인증이나 요청 형식에 맞출 수 없다면 Listener를 검토합니다.
직접 발행할 때는 스트림의 데이터셋 RID, 브랜치 이름과 인증 토큰이 필요합니다. 앱의 호출 허용 범위와 스트림 리소스 권한도 각각 설정해야 합니다.
스트림 생성
Foundry의 대상 프로젝트에서 + New > Stream을 선택합니다.
가상 센서 예제의 스키마는 다음과 같습니다. 예제에서는 세 필드를 모두 필수로 사용합니다.
| 열 | 자료형 | 의미 |
|---|---|---|
sensor_id | String | 센서 식별자 |
temperature | Double | 온도 값 |
created_at | Timestamp | 측정 시각 |
Generate from JSON sample...에서 JSON 예시로 스키마를 만들 수도 있습니다. 생성한 자료형과 Nullable 설정이 실제 전송 데이터에 맞는지 확인합니다.
처리량은 Normal로 선택하여 단일 파티션 스트림으로 시작합니다. 생성 화면의 Normal은 최대 5 MB/s 정도의 처리량에 적합하며 도착 순서를 보장하는 설정입니다. Very high는 더 높은 처리량과 연산 비용을 위한 선택이며 도착 순서를 보장하지 않습니다. 서로 다른 처리량 설정에 같은 순서 가정을 적용하지 않습니다.
여러 파티션을 사용할 때는 동일한 키 값의 레코드 순서를 다루기 위해 Keys를 설정합니다. 같은 키에 대한 순서와 서로 다른 키 사이의 전역 순서는 구분해야 합니다. 관계형 데이터베이스의 변경을 보낸다면 CDC 구성을 검토합니다. CDC 선택은 스트림 생성 후 변경할 수 없습니다.
모든 검증 오류를 해결한 뒤 Create stream을 선택합니다. 화면 아래 오류 표시의 툴팁에서 상세 내용을 확인할 수 있습니다.
연결 방식과 인증 선택
Connect의 Connect via API에서 사용할 언어를 선택합니다. HTTP 요청을 보낼 수 있는 언어를 사용할 수 있으며 cURL, Python, Node.js와 Java 예제가 제공됩니다. 선택하면 Push 구성 화면으로 이동합니다.
인증은 다음 두 경로를 구분합니다.
| 방식 | 용도 |
|---|---|
Push with a third-party application | 권장 방식입니다. Client credentials grant를 사용하는 앱과 서비스 사용자로 발행합니다. |
Push with a personal token | 개인 토큰을 사용하는 시험용 경로입니다. 운영 연결에는 앱 인증을 사용합니다. |
Client credentials 앱 준비
앱에는 Client ID, Client Secret과 서비스 사용자가 연결됩니다. 플랫폼 인스턴스에서 사용할 수 있는 생성 경로를 선택합니다.
Developer Console
권장 경로는 Developer Console입니다. 애플리케이션 유형에서 Backend service, 권한 단계에서 Application permissions를 선택합니다. 이 선택으로 client credentials grant가 활성화됩니다. 생성된 Client ID와 Secret을 확보한 뒤 Push 화면에 입력합니다. 아래 Control Panel 경로의 별도 grant 활성화 단계를 다시 수행할 필요는 없습니다.
Control Panel
Developer Console을 사용할 수 없다면 Push 화면에서 Go to third-party applications를 선택합니다.
-
관리 화면에서
Register new application을 선택합니다. -
앱 이름을 정하고 클라이언트 유형을
Server application으로 설정합니다. -
Create를 선택하고 Client ID와 Client Secret을 안전하게 보관합니다. Client Secret은 이 화면을 떠난 뒤 다시 볼 수 없습니다. -
Push 화면에 Client ID와 Secret을 입력합니다.
-
Configuring the Application의Manage application을 선택합니다. -
Client credentials grant를 켜고Save를 선택합니다.
어느 생성 경로를 사용하든 애플리케이션의 Operation restrictions에는 api:use-streams-write 작업이 허용되어야 합니다. 아래 공개 V2 발행 API의 OAuth scope인 api:streams-write와 표기가 다르므로 두 설정을 혼동하지 않습니다.
앱에 스트림 권한 부여
서비스 사용자는 기본적으로 리소스 접근 권한이 없습니다. Client ID를 사용하여 스트림을 공유합니다.
-
Push 화면의
Using Your New Application에서 Client ID를 확인합니다. -
오른쪽 위
Share로 Details의Roles탭을 엽니다. -
Client ID를 검색하여 앱의 서비스 사용자를 찾습니다.
-
+에서Editor역할을 선택하고 패널 아래Save를 선택합니다. -
Push 화면으로 돌아와
Next step을 선택합니다.
앱의 작업 제한, 토큰의 OAuth scope와 리소스의 Editor 역할은 서로 다른 조건입니다. 유효한 토큰만 발급받았다고 스트림 쓰기 권한이 자동으로 생기지는 않습니다.
공개 V2 배치 발행 API
공개 API에서 여러 레코드를 보내는 요청은 다음과 같습니다.
POST /api/v2/highScale/streams/datasets/{datasetRid}/streams/{streamBranchName}/publishRecords
경로의 datasetRid와 streamBranchName은 필수 문자열입니다. OAuth scope는 api:streams-write입니다.
| JSON 본문 필드 | 자료형과 동작 |
|---|---|
records | 문자열 키와 임의의 JSON 값을 가진 레코드 맵의 목록입니다. API 스키마상 선택 필드이며, 데이터를 발행할 때 이 목록을 지정합니다. |
viewRid | 선택적 문자열입니다. 지정하면 그 뷰에 해당하는 스트림에만 쓰고, 생략하면 해당 브랜치의 최신 스트림에 씁니다. 기반 스트림을 명시적으로 고정할 필요가 있을 때 사용하는 고급 설정입니다. |
본문 자체는 JSON 객체여야 합니다. 레코드는 스트림 스키마에 맞는지 검증되며, 하나 이상이 잘못되면 해당 배치가 거부됩니다. Timestamp를 스트림 키로 사용하는 필드는 Unix epoch 밀리초로 보내야 합니다. 다음 센서 예제도 밀리초 값을 사용합니다.
records.json의 가상 입력은 다음과 같습니다. 스키마에서 필수로 설정한 created_at도 포함합니다.
{
"records": [
{
"sensor_id": "sensor4",
"temperature": 4.132,
"created_at": 1731426022784
}
]
}
V2의 records 목록에는 레코드의 열 값을 직접 넣습니다. Push 화면이 다른 발행 API에 대해 제시하는 value 래퍼 배열 형식과 혼용하지 않습니다. 화면에서 생성한 요청을 그대로 사용할 경우에는 그 엔드포인트와 본문 형식을 한 쌍으로 사용합니다.
권한이 없으면 PublishRecordsToStreamPermissionDenied 오류와 PERMISSION_DENIED 코드가 반환될 수 있으며, 오류 매개변수는 datasetRid, streamBranchName입니다. 발행 메서드는 결과 레코드 목록을 응답으로 돌려주는 인터페이스가 아닙니다.
cURL로 토큰 발급과 발행
Bash, jq와 --fail-with-body, --header @-를 지원하는 cURL을 준비합니다. Windows에서도 이 예제는 Bash 환경에서 실행합니다. 다음 값을 환경 변수로 제공합니다.
| 변수 | 입력 |
|---|---|
FOUNDRY_URL | 실제 Foundry의 HTTPS 기본 URL |
CLIENT_ID | 등록한 앱의 Client ID |
CLIENT_SECRET_FILE | Client Secret만 담은 로컬 파일의 경로 |
DATASET_RID | 대상 스트림의 데이터셋 RID |
STREAM_BRANCH | 실제 스트림 브랜치 이름 |
RECORDS_FILE | 앞의 V2 본문 형식으로 작성한 JSON 파일 경로 |
Client Secret 파일은 소유자만 읽을 수 있도록 보호하고, 값 뒤에 줄바꿈을 넣지 않습니다. cURL의 파일 기반 URL 인코딩은 줄바꿈도 값에 포함하기 때문입니다. 비밀 정보와 액세스 토큰을 URL이나 명령 인수에 넣지 않도록 토큰은 폼 본문으로 교환하고 발행 인증 헤더는 표준 입력으로 전달합니다.
set -euo pipefail
set +x
: "${FOUNDRY_URL:?Foundry HTTPS 기본 URL을 설정하세요}"
: "${CLIENT_ID:?Client ID를 설정하세요}"
: "${CLIENT_SECRET_FILE:?Client Secret 파일 경로를 설정하세요}"
: "${DATASET_RID:?스트림 데이터셋 RID를 설정하세요}"
: "${STREAM_BRANCH:?스트림 브랜치 이름을 설정하세요}"
: "${RECORDS_FILE:?V2 발행 JSON 파일 경로를 설정하세요}"
BASE_URL="${FOUNDRY_URL%/}"
RID_PATH="$(printf '%s' "$DATASET_RID" | jq -sRr @uri)"
BRANCH_PATH="$(printf '%s' "$STREAM_BRANCH" | jq -sRr @uri)"
trap 'unset ACCESS_TOKEN' EXIT
ACCESS_TOKEN="$(
curl --silent --show-error --fail-with-body \
--request POST \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret@$CLIENT_SECRET_FILE" \
--data-urlencode 'scope=api:streams-write' \
"$BASE_URL/multipass/api/oauth2/token" |
jq -er '.access_token | select(type == "string" and length > 0)'
)"
printf 'Authorization: Bearer %s\n' "$ACCESS_TOKEN" |
curl --silent --show-error --fail-with-body \
--request POST \
--header @- \
--header 'Content-Type: application/json' \
--data-binary "@$RECORDS_FILE" \
"$BASE_URL/api/v2/highScale/streams/datasets/$RID_PATH/streams/$BRANCH_PATH/publishRecords"
토큰 응답의 expires_in은 유효 기간을 초로 나타냅니다. 반복 발행 프로그램은 유효 기간 안에서 토큰을 재사용하고 만료 전에 새 토큰을 발급받아야 합니다. 위 예제는 한 배치를 발행하는 흐름입니다. Client credentials 요청은 일반 사용자를 대신하지 않고 앱의 서비스 사용자 권한으로 동작합니다.
수신 확인과 후속 처리
발행 후 스트림 화면에서 레코드가 들어오는지 확인합니다. 입력 데이터를 바꾸려면 JSON 파일의 records 값을 실제 스키마에 맞춰 수정합니다.
화면의 Test with JSON 카드를 펼쳐 시험 레코드를 보낼 수도 있습니다. 이 경우에는 해당 카드가 요구하는 입력 형식과 스키마를 사용합니다.
Start pipelining을 선택하면 Pipeline Builder에서 스트림의 후속 변환을 구성할 수 있습니다. 수신 인증과 리소스 권한이 맞는지, 필수 필드가 빠지지 않았는지부터 확인한 뒤 처리 파이프라인으로 연결합니다.