Openflow Connector for Shopify 문제 해결

Openflow Connector for Shopify 문제 해결

이 페이지에서는 Shopify용 Openflow Connector에서 겪을 수 있는 흔한 문제들을 해결하는 방법을 설명해요. 테이블이 생성되지 않는 문제부터 인증·권한 오류, 벌크 작업 실패, 스로틀링까지 상황별로 다룹니다.

출처: Snowflake 문서

본문

Note

이 커넥터는 Snowflake Connector Terms에 의해 규율됩니다.

이 토픽은 Shopify용 Openflow Connector를 문제 해결하는 방법을 설명합니다.

테이블이 나타나지 않거나 비어 있음

  1. apiType이 Objects to Sync 파라미터에 나열되고 철자가 올바른지 확인하세요(매칭은 대소문자 구분이 없지만 값은 Shopify Admin GraphQL API의 쿼리 루트에 해당해야 합니다).

  2. Shopify dev 앱이 해당 객체 유형에 대한 일치하는 읽기 스코프를 가졌는지 확인하세요. 예를 들어 orders는 read_orders가 필요합니다. 스코프가 없으면 다른 객체에는 영향 없이 해당 객체 유형에 대해서만 접근 오류나 빈 결과가 발생합니다.

  3. 사용자 정의 객체 정의를 사용한다면 Object Definitions Override 값이 유효한 JSON이고 최상위 배열인지 확인하세요. 그런 다음 컨트롤러 서비스를 다시 활성화하세요.

  4. 자동 탐색에 의존한다면 Enable Introspection이 true로 설정되어 있는지 확인하세요.

OAuth2 토큰 요청에서 UnknownHostException으로 커넥터 실패

커넥터 로그에 java.net.UnknownHostException: <your_store>.myshopify.com으로 인한 OAuth2 access token request failed 같은 오류가 있으면, 런타임이 Shopify 도메인에 도달할 수 없다는 뜻입니다. 이는 커넥터의 External Access Integration(EAI)이 생성되지 않았거나, EAI에 대한 USAGE가 런타임의 execute-as 역할에 부여되지 않았음을 의미합니다.

Creating network rules and external access integrations의 단계를 따라 네트워크 규칙과 EAI를 만들고 execute-as 역할에 통합에 대한 USAGE를 부여하세요. 다음 섹션에 설명된 대로 두 필수 엔드포인트를 모두 네트워크 규칙의 VALUE_LIST에 추가하세요.

벌크 결과 다운로드 시 UnresolvedAddressException으로 커넥터 실패

storage.googleapis.com URL에 접근할 때 커넥터 로그에 java.net.ConnectException 또는 java.nio.channels.UnresolvedAddressException이 있는 WebClientServiceException이 있으면, EAI 네트워크 규칙의 VALUE_LIST에 storage.googleapis.com:443이 없는 것입니다. 벌크 작업이 완료된 뒤 Shopify는 결과 파일에 대한 서명된 Google Cloud Storage URL을 반환하며, 커넥터는 그 호스트에 도달해 다운로드해야 합니다.

ALTER NETWORK RULE ... SET VALUE_LIST는 기존 목록 전체를 덮어쓰므로, 변경하기 전에 규칙에 무엇이 있는지 먼저 확인하세요:

DESCRIBE NETWORK RULE OPENFLOW_<RUNTIME_NAME>_NETWORK_RULE;

그런 다음 기존 항목에 두 필수 엔드포인트를 더해 네트워크 규칙을 업데이트하세요:

ALTER NETWORK RULE OPENFLOW_<RUNTIME_NAME>_NETWORK_RULE
  SET VALUE_LIST = (
    -- existing entries from the value_list column above,
    '<your_store>.myshopify.com:443',
    'storage.googleapis.com:443'
  );

HTTP 401 Unauthorized로 커넥터 실패

커넥터가 [API] Invalid API key or access token (unrecognized login or wrong password) 오류와 함께 HTTP 401 응답을 받으면 OAuth2 접근 토큰이 유효하지 않거나 폐기된 것입니다. 다음을 확인하세요:

  1. Shopify Client ID와 Shopify Client Secret 파라미터가 Dev Dashboard에서 앱의 Settings » Credentials의 자격 증명과 일치하는지 확인하세요.

  2. 앱이 스토어에 설치되어 있는지 확인하세요. 앱이 한 번이라도 제거되었다면 기존 토큰은 폐기됩니다. 필요하면 앱을 재설치한 뒤 새 토큰을 얻기 위해 커넥터를 다시 시작하세요.

  3. 앱이 릴리스되었는지 확인하세요. 릴리스되지 않은 앱은 인증할 수 없습니다.

객체 유형에 대한 쿼리가 ACCESS_DENIED로 실패

커넥터는 두 가지 이유로 객체 유형에 대한 GraphQL ACCESS_DENIED 오류를 받을 수 있습니다:

  • 스코프 누락: 오류 메시지는 Access denied for <object> field.입니다. 앱에 필요한 읽기 스코프가 없습니다. Dev Dashboard에서 해당 스코프를 추가하고(예: orders에 read_orders), 업데이트된 앱 버전을 릴리스한 뒤 스토어에 앱을 재설치하세요.

  • 보호된 고객 데이터 미승인: 오류 메시지는 This app is not approved to access the <Object> object.입니다. 해당 객체는 Shopify의 보호된 고객 데이터 승인이 필요합니다. Dev Dashboard에서 앱의 API access 설정으로 접근 요청을 제출하세요. 자세한 내용은 Shopify 개발자 문서의 Protected customer data를 참고하세요.

오류가 객체 유형 전체가 아니라 단일 필드에서 발생한다면 하나의 필드에 대한 접근 거부 오류를 참고하세요.

하나의 필드에서 접근 거부 오류로 쿼리 실패

일부 Shopify Admin GraphQL 필드는 읽는 데 쓰기 스코프가 필요합니다. 예를 들어 고객 마케팅 URL 필드(marketingUnsubscribeUrl, openTrackingUrl)는 write_customers가 필요합니다. 앱에 필요한 스코프가 없으면 Shopify API가 해당 필드에 대해 오류를 반환하고 전체 객체의 쿼리가 실패합니다.

해결책은 쓰기 스코프를 부여하는 대신 쿼리에서 필드를 제거하는 것입니다. ignoredFields는 최상위 항목의 선행 이름에만 일치하며 중첩 하위 선택에는 적용되지 않습니다:

  • 최상위 필드(graphqlFields의 직접 항목): graphqlFields에서 제거하거나 그 이름을 ignoredFields에 추가하세요.

  • 중첩 필드(하위 선택 내, 예: defaultEmailAddress { ... } 안의 marketingUnsubscribeUrl): graphqlFields에서 부모 항목의 하위 선택을 편집해 문제 필드를 제거하세요.

수정된 정의를 Object Definitions Override 파라미터로 제공하세요. 자세한 내용은 Shopify용 Openflow Connector의 객체 정의 오버라이드를 참고하세요.

오래된 주문 기록이 누락됨(약 60일만 존재)

read_orders 스코프는 기본적으로 지난 60일 내에 생성된 주문에 대한 접근을 제한합니다. 전체 주문 기록을 백필하려면 Shopify 앱에 read_all_orders도 부여되어야 합니다. 이 스코프는 Dev Dashboard에서 앱의 API access 설정을 통한 접근 요청이 필요합니다.

read_all_orders를 부여한 뒤 의 orders 객체 상태를 리셋해 벌크 로드가 다시 실행되고 전체 기록을 캡처하도록 하세요.

커넥터가 시작되지 않거나 Object Registry 서비스가 INVALID

이것은 거의 항상 잘못된 Object Definitions Override 값 때문에 발생합니다. 값은 구문적으로 유효한 JSON이어야 하고 최상위 배열이어야 합니다. 잘못된 값이나 배열이 아닌 값은 StandardShopifyObjectRegistryService가 활성화되는 것을 막고 커넥터가 시작에 실패합니다.

진단하려면:

  1. Controller Services 패널을 열고 StandardShopifyObjectRegistryService를 선택합니다.

  2. "Invalid JSON" 또는 "Must be a JSON array of object definitions" 같은 파싱 오류가 있는지 서비스 게시판(bulletin)을 확인합니다.

  3. JSON을 고치고 파라미터를 다시 적용한 뒤 서비스를 다시 활성화합니다.

적용하기 전에 JSON을 검증할 수 있습니다:

python3 -c "import json, sys; d = json.load(open('override.json')); sys.exit(0 if isinstance(d, list) else 1)"

벌크 작업이 즉시 실패

다음 시나리오는 벌크 작업이 즉시 실패하거나 멈추게 할 수 있습니다.

잘못된 정렬 키

sortKeys의 지원되지 않는 값은 전체 벌크 작업을 실패시킵니다. 객체 정의에서 정렬 키를 제거하거나 수정하세요. sortKeys를 생략하는 것은 항상 안전합니다.

벌크 작업이 이미 진행 중

Shopify는 상점당 한 번에 하나의 벌크 작업만 허용합니다. 프로세서는 다음 주기에 자동으로 재시도합니다. 진행 중인 작업이 해제되지 않으면 같은 상점의 다른 통합이 벌크 슬롯을 잡고 있을 수 있습니다.

너무 많거나 너무 깊게 중첩된 연결

Shopify Bulk Operations API는 쿼리당 최대 5개 연결과 2단계 중첩을 허용합니다. Include Metafields가 활성화되면 연결 하나를 소비합니다. 하위 연결을 줄이거나 평탄화해 이 한도 안에 머물게 하세요.

진행 없이 벌크 작업이 멈춤

매우 큰 데이터셋은 완료하는 데 상당한 시간이 걸릴 수 있습니다. 벌크 작업이 오랜 시간 동안 진행되지 않으면 멈추었을 수 있습니다. Shopify 관리자에서 벌크 작업 상태를 확인하거나, 영향을 받는 객체를 리셋해 다시 제출하세요.

Snowflake의 중복 또는 누락 레코드

초기 로드 직후의 중복은 벌크-증분 전환 중에 예상되는 현상입니다. 병합은 복합 키 (ID, SHOP_URL)을 사용하므로 대상 테이블은 첫 증분 실행 후 수렴합니다. 조치가 필요 없습니다.

누락 또는 업데이트되지 않는 레코드: 증분 워터마크가 영향받은 레코드를 지나서 진행되었을 수 있습니다. 객체별 상태를 검사해 상위 워터마크(high watermark)를 확인하세요. 워터마크가 잘못되었다면 객체를 리셋해 벌크 로드를 다시 실행하세요.

특히 orders의 경우 60일 주문 기록 창이 원인이 아닌지도 확인하세요. 자세한 내용은 오래된 주문 기록이 누락됨을 참고하세요.

첫 실행에서 증분 프로세서가 retry나 failure로 라우팅

GetShopifyIncremental 프로세서는 각 객체 유형의 일회성 벌크 로드가 완료될 때까지 retry나 failure로 라우팅합니다. 이는 첫 실행에서 예상되는 동작입니다. 더 조사하기 전에 벌크 로드가 끝나도록 두세요.

"Invalid search field: "으로 증분 실패

이 오류는 객체의 incrementalField가 반환된 타입에는 존재하지만 쿼리 루트의 query: 인자로 필터를 받아들여지지 않을 때 GetShopifyIncremental 게시판에 나타납니다.

해결책: 객체의 Object Definitions Override 항목에서 supportsIncremental을 false로, refreshStrategy를 FULL_PERIODIC으로 설정하세요. 객체는 벌크 로드를 한 번 수행하고 증분 폴링하지 않습니다. 새로고침하려면 객체 상태를 리셋하세요.

영향받는 일반적인 객체: codeDiscountNodes, automaticDiscountNodes. 증분 지원과 함께 할인을 동기화하려면 discountNodes 쿼리 루트를 사용하세요.

오버라이드 JSON을 편집한 뒤 StandardShopifyObjectRegistryService를 다시 활성화하세요.

Shopify에서 스키마 변경

스키마 진화는 지원되지 않습니다. Shopify 객체의 필드가 변경되면(필드 추가·제거), 영향을 받는 객체의 커넥터 상태를 리셋하고 해당 Snowflake 테이블을 삭제해 업데이트된 스키마로 다시 스냅샷하세요.

삭제가 Snowflake에 나타나지 않음

다음을 순서대로 확인하세요:

  1. 객체 유형이 삭제 감지를 지원해야 합니다. Shopify Events API에서 destroy 이벤트를 발생시키는 객체 유형만 추적할 수 있습니다. 자세한 내용은 삭제 처리 방법을 참고하세요.

  2. 객체 유형이 Objects to Track for Deletes 파라미터에 나열되어야 합니다.

  3. 삭제 폴링이 시작되기 전에 해당 객체 유형의 초기 벌크 로드가 완료되어야 합니다.

  4. 안전 버퍼(기본 5분)보다 최근의 삭제 이벤트는 의도적으로 지연됩니다.

  5. API 크레딧이 속도 제한 임계값(기본 500포인트) 아래로 떨어지면 삭제 폴링은 양보(yield)합니다. 커넥터가 속도 제한 임계값 아래에 있고 양보 중임을 나타내는 메시지가 있는지 프로세서 게시판을 확인하세요.

오류: "first cannot exceed 250"

이 오류는 일반(증분) 쿼리가 first:를 Shopify의 하드 한도인 250보다 높게 설정할 때 발생합니다. 전체 오류: "first cannot exceed 250. To query larger amounts of data with fewer limits, bulk operations should be used instead."

Page Size 파라미터와 Object Definitions Override의 childFields 정의의 pageSize 값을 확인하세요. 둘 다 250 이하여야 합니다.

이 한도는 초기 벌크 로드에는 적용되지 않습니다: Shopify Bulk Operations API는 first: 인자를 무시하고 모든 레코드를 반환합니다. pageSize 값보다 많은 하위 항목을 가진 부모 객체의 경우, 초기 벌크 로드만 전체 하위 집합을 캡처하며 증분 실행은 부모당 pageSize로 제한됩니다.

지속적인 스로틀링

객체가 많은 고부하 스토어는 오랜 기간 속도 제한 상태로 남을 수 있습니다. API 사용량을 줄이려면:

  • Sync Schedule과 Deletes Schedule 간격을 늘리세요.

  • Objects to Sync의 항목 수를 줄이세요.

  • 메타필드 데이터가 필요하지 않다면 Include Metafields를 비활성화하세요.

SPCS 또는 SNOWFLAKE_MANAGED 배포에서 StandardPrivateKeyService가 INVALID로 표시

StandardPrivateKeyService 컨트롤러는 KEY_PAIR 인증을 사용하는 BYOC 배포에서만 사용됩니다. SPCS 배포와 SNOWFLAKE_MANAGED 인증을 사용하는 BYOC 배포에서는 이 컨트롤러가 사용되지 않으며 INVALID 상태로 표시될 수 있습니다.

이것은 예상된 동작이며 커넥터에 영향이 없습니다. 이 컨트롤러의 상태와 무관하게 커넥터는 올바르게 동작합니다. 컨트롤러를 삭제하면 플로우 정의에 로컬 변경이 생기므로 Snowflake는 그대로 두는 것을 권장합니다.

더 알아보기 (Learn more)