AWS/AWS Marketplace

AWS Marketplace 연동 가이드 | 03. ResolveCustomer

행운개발자 2024. 1. 17. 02:25
728x90

AWS Marketplace 연동 가이드 | 01. AWS Marketplace Seller 계정 생성부터 x-amzn-marketplace-token 토큰 수신까지

AWS Marketplace 연동 가이드 | 02. AWS Marketplace Client 생성하기

AWS Marketplace 연동 가이드 | 03. ResolveCustomer

AWS Marketplace 연동 가이드 | 04. BatchMeterUsage


ResolveCustomer 호출하기

ResolveCustomer는 token을 사용해서 CustomerIdentifier, CustomerAWSAccountId, ProductCode 3가지 필드를 조회합니다. 이 3가지 필드들은 모두 영구적으로 저장되어야합니다.

https://docs.aws.amazon.com/marketplace/latest/userguide/saas-integrate-subscription.html#saas-subscription-validate-customer

resolveCustomer는 아래와 같이 구현했습니다

아래의 코드에서 getAwsMarketplaceClient() 코드는 아래의 Gist 링크를 참고해주세요

https://gist.github.com/hwanseok-dev/570c0d124c31cba459a60d689d0a15b6#file-createawsmarketplaceclient-java-L86

ResolveCustomerResult resolveCustomer(String token) throws WhaTapError {
    // create request
    ResolveCustomerRequest resolveCustomerRequest = new ResolveCustomerRequest();
    resolveCustomerRequest.setRegistrationToken(token);
    int retry = 0;
    final int RETRY_MAX = conf.aws_marketplace_metring_retry_count;
    while (retry < RETRY_MAX) {
        try {
            return getAwsMarketplaceClient().resolveCustomer(resolveCustomerRequest);
        } catch (AWSMarketplaceMeteringException e) {
            logger.error("[AWS MP] An internal error has occurred. Retry request. retry count : {}/{}, token : {}, errMsg : {}",
                    retry, RETRY_MAX, token, e.getMessage());
            retry++;
            ThreadUtil.sleep(conf.aws_marketplace_metring_retry_sleep_time);
        } catch (Exception e) {
            logger.error("[AWS MP] " + e.getMessage(), e);
            throw new WhaTapError(ModuleName.ACCOUNT, ErrorType.INTERNAL_SERVER_ERROR);
        }
    }
    logger.error("[AWS MP] Retry failed. token : {}", token);
    throw new WhaTapError(ModuleName.ACCOUNT, ErrorType.INTERNAL_SERVER_ERROR);
}

ResolveCustomer API를 보면 InternalServiceErrorException 이 발생한 경우에는 retry를 해야한다고 명시되어 있습니다. config 값으로 retry를 수행하는 횟수를 런타임에 변경할 수 있도록 했습니다. InternalServiceErrorException 가 아닌 AWSMarketplaceMeteringException 는 400 에러로 처리했습니다.

ResolveCustomer 응답 저장하기

응답을 어떤 형태로 저장할지 결정하기 위해 AWS MP의 연동 흐름을 다시 짚어보겠습니다.

  1. 사용자는 AWS MP 구독을 합니다.
  2. 사용자는 Fulfillment URL을 통해서 신규 계정 생성 페이지로 Redirect 됩니다.
  3. AWS MP Token 정보는 신규 계정이 생성될 때 서버로 전송됩니다.

위와 같은 흐름을 고려해서 ResolveCustomer API 호출이후 신규 계정 생성구독 정보 저장이라는 2가지 이벤트가 순차적으로 수행되어야 합니다.

여기서부터는 상황에 따라 많이 달라집니다. 예를 들면 구현하면 아래와 같이 할 수 있습니다.

MonitoringAccountDTO created;
if (conf.email_verify) {
    created = accountService.createUnverifiedAccount(loginAccount);
} else {
    created = accountService.activateAccount(loginAccount);
}
if (created != null) {
    // aws marketplace 전용 계정 생성인 경우에만 토큰이 전달된다
    if (conf.enable_aws_marketplace && StringUtil.isNotEmpty(awsMarketplaceToken)) {
        // 이메일 인증 여부와 상관없이 항상 구독 정보를 저장한다
        accountService.createAwsMarketplaceSubscribe(created.getId(), awsMarketplaceToken);
    }
}

AWS MP 구독 정보 저장하기

AWS MP를 구독하는 과정에서 반드시 새로운 계정이 생성되는 동선을 적용했습니다. 그렇기 때문에 로그인 및 계정 생성 과정에서 AWS MP 구독 정보가 함께 저장되어야 합니다.

@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(indexes = {
        @Index(name = "INDEX_ACCOUNT_ID", columnList = "accountId")
}, uniqueConstraints = {
        @UniqueConstraint(name = "UNIQUE_ACCOUNT_ID", columnNames = "accountId")
})
public class AwsMarketplaceSubscribe {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private Integer id;

    @Column(name = "AccountId")
    private Integer accountId;

    // 구독 이후에 발급되는 "x-amzn-marketplace-token" 토큰
    @Column(name = "Token", nullable = false)
    private String token;

    @Column(name = "CustomerAWSAccountId", nullable = false)
    private String customerAWSAccountId;

    @Column(name = "CustomerIdentifier", nullable = false)
    private String customerIdentifier;

    @Column(name = "AwsProductCode", nullable = false)
    private String awsProductCode;

        ... 생략 ...
}

위에서 생각한 모델링에서는 Account : AwsMarketplaceSubscribe = 1 : N이지만, 하나의 계정에서는 하나의 AWS MP만 구독할 수 있다.라는 제약사항(개발 일정을 고려한 최소 개발 범위)을 반영해 UniqueConstraint 를 추가했습니다. Account → AwsMarketplaceSubscrbie 방향으로 조회 흐름이 필요하기 때문에 Index 를 추가했습니다.

💡customerAWSAccountId, customerIdentifier, awsProductCode

AwsMarketplaceSubscribe 클래스의 필드들은 ResolveCustomer API를 사용해서 조회되는 필드들입니다.

728x90