//------------------------------------------------------------------------------

// 기존 푸쉬 발송의 문제점

//------------------------------------------------------------------------------

우리 디비에 저장된 디바이스의 푸쉬토큰을

차례로 읽으면서 한명 한명한테 발송함.

시간이 오래걸림.

서버에 부하가 좀 생김.

그래서 aws sns 로 바꾸기로 함.



//------------------------------------------------------------------------------

// 금액

//------------------------------------------------------------------------------

1백만건당 1달라.

처음 1백만건은 무료.

아주 굿.



//------------------------------------------------------------------------------

// sns application

//------------------------------------------------------------------------------

어떤 푸쉬 시스템을 사용할지 결정하는 것

나는 아래의 3개를 생성하였음.

- ios development

- ios production

- android


ios는 애플개발자센터에서 푸쉬인증서(p12 파일) 를 다운받아서. aws sns 에 넣어야 함.

android는 구글개발자센터에서 푸쉬 서버키를 복사해서. aws sns 에 넣어야 함.


사용자 디바이스에서 받은 푸쉬토큰을 각각의 application 안에 넣어주고.

리턴값으로 받은 endpoint_arn 을 디비에 저장해야 함.



//------------------------------------------------------------------------------

// 한건 푸쉬 발송

//------------------------------------------------------------------------------

디비에 저장한 endpoint arn 값을 이용해서. 직접 푸쉬 발송 할수 있음.

이럴경우 기존 방식과 동일함.

기존방식은 ios 인지 android 인지 구분하여 푸쉬 발송 로직이 달라졌지만.

sns를 이용하면 동일한 로직으로 보낼수 있음.



//------------------------------------------------------------------------------

// sns topic

//------------------------------------------------------------------------------

대량 발송용. 주기적인 특정 대상들에게 발송용.


* 순서

1. 특정한 토픽을 생성한다.

2. 그 토픽에 발송 대상자들의 endpoint arn 을 추가한다 (=구독자를 추가한다)

3. 그 토픽에 푸쉬를 보내면. 그 토픽의 구독자들에게 모두 푸쉬가 발송된다.


사실 대량발송용 이라고 해서. 되게 편할줄 알았는데. 별로 그렇지도 않다.

기존방식은 루프돌면서 한건씩 발송하지만

토픽을 이용하면 루프돌면서 구독자들을 추가해야 하기때문에 별 차이가 없음.


그런데 만약 전체 회원에게 푸쉬를 발송할 경우는 아주 유용하다.

전체회원발송용 토픽을 먼저 생성한후 (all_topic 이라 하자)

사용자에게 받은 푸쉬토큰을 위에서 application 에 추가할때 all_topic 에도 추가한다.

(기존 사용자들의 데이타는 배치작업으로 추가하고)

그리고 전체회원에게 푸쉬 발송할때는. all_topic 에만 한번 보내면 되니까. 무척 좋음.


특정한 조건의 사용자들만 디비에서 뽑아서 푸쉬발송하려면.

위의 1, 2, 3번 과정을 거쳐야 함.



//------------------------------------------------------------------------------

// 사용자가 푸쉬 수신 수락했을때 예제

//------------------------------------------------------------------------------

// sns application 의 endpoint 생성

// $sns_application_arn 위에서 생성한 application 의 arn

// $push_token : 사용자의 푸쉬토큰

// $endpoint_arn : 리턴받은 endpoint arn

$param = ['Attributes'=>[],

          'CustomUserData'=>'',

          'PlatformApplicationArn'=>$sns_application_arn,

          'Token'=>$push_token];

$sns_client = AWS::createClient('sns');

$sns_result = $sns_client->createPlatformEndpoint($param);

$endpoint_arn = $sns_result['EndpointArn'];


// 전체회원topic에 subscription 추가

// $sns_topic_arn : 미리 만들어둔 전체회원topic arn

$param = ['Endpoint'=>$endpoint_arn,

          'Protocol'=>'application',

          'TopicArn'=>$sns_topic_arn];

$sns_client = AWS::createClient('sns');

$sns_result = $sns_client->subscribe($param);

$subscription_arn = $sns_result['SubscriptionArn'];


// $endpoint_arn, $subscription_arn 우리디비에 저장

update ...



//------------------------------------------------------------------------------

// 사용자가 푸쉬 수신 거부했을때 예제

//------------------------------------------------------------------------------

// sns application 의 endpoint 삭제

$param = ['EndpointArn'=>$sns_endpoint_arn];

$sns_client = AWS::createClient('sns');

$sns_client->deleteEndpoint($param);


// 전체회원topic의 subscription 삭제

// $sns_subscription_arn : 전체회원topic에 추가할때 리턴받은. 구독자arn

$param = ['SubscriptionArn'=>$sns_subscription_arn];

$sns_client->unsubscribe($param);


// $endpoint_arn, $subscription_arn 우리디비에서 삭제

update ...



//------------------------------------------------------------------------------

// 특정대상 사용자에게 푸쉬 발송할때 예제

//------------------------------------------------------------------------------

// 푸쉬 대상자 조회

select 어쩌구...


// sns topic 생성

// $topic_arn : 토픽이 생성된후 리턴받은 topic arn

$param = ['Name'=>특정한토픽이름];

$sns_client = AWS::createClient('sns');

$result = $sns_client->createTopic($param);

$topic_arn = $result['TopicArn'];


// 푸쉬 대상자들만큼 루프

// $sns_endpoint_arn : 디비에 저장되어 있던 endpoint arn

foreach(...)

{

    $param = ['Endpoint'=>$sns_endpoint_arn,

              'Protocol'=>'application',

              'TopicArn'=>$topic_arn];

    $sns_client->subscribe($param);

}


// sns topic 에 발송.

// $message_ios : 토픽에 속한 ios 디바이스에 보낼때의 메세지

// $message_android : 토픽에 속한 android 디바이스에 보낼때의 메세지

$message = array_merge(array('default'=>''), $message_ios, $message_android);

$param = ['Message'=>json_encode($message),

          'MessageStructure'=>'json',

          'TopicArn'=>$topic_arn];

$sns_client = AWS::createClient('sns');

$result = $sns_client->publish($param);



//------------------------------------------------------------------------------

// 전체회원에게 푸쉬발송 예제

//------------------------------------------------------------------------------

위에서 토픽에 발송하는 것과 똑같음.

TopicArn 에 전체회원topic arn 을 넣어주면 됨

(나는 전체회원topic arn 값을 하드코팅 했음)



//------------------------------------------------------------------------------

// 직접 푸쉬 발송 예제

//------------------------------------------------------------------------------

// sns endpoint 에 직접 푸쉬발송.

// $message : json 형식의 푸쉬 메세지 (ios, android 형식이 다름)

// $sns_endpoint_arn : 디비에 저장되어 있던 endpoint arn

$param = ['Message'=>$message),

          'MessageStructure'=>'json',

          'TargetArn'=>$sns_endpoint_arn];

$sns_client = AWS::createClient('sns');

$sns_result = $sns_client->publish($param);



//------------------------------------------------------------------------------

// 발송할수 없는 endpoint arn 들 삭제하기

//------------------------------------------------------------------------------

사용자가 앱을 삭제했다던가의 이유로 푸쉬를 받을수 없는 경우를 찾아서. 없애자

(나는 이걸 스케쥴로 만들어. 우리 디비에서 1분마다 50건씩 랜덤하게 조회해 sns 에서 상태체크하였음)

(반대로 sns 에서 전체리스틀 받아서 처리하는 방식도 있을거 같음)

(발송할수 없는 상태는. 푸쉬를 한번이라도 보내야만 생길것임. 푸쉬를 보낸후에야 못보낸다는걸 알수 있음)


// 우리 디비에서 순차적으로 endpoint arn 을 가져옴

select ...


// 루프돌면서. endpoint arn 의 상태를 가져와서 확인.

// $sns_endpoint_arn : 우리디비에 저장된 endpoint arn

// $sns_subscription_arn : 우리디비에 저장된 전체회원topic 구독자arn

foreach(...)

{

    $param = ['EndpointArn'=>$sns_endpoint_arn];

    $sns_client = AWS::createClient('sns');

    $sns_result = $sns_client->getEndpointAttributes($param);


    // 발송할수 있는 상태가 아니면

    if(!$sns_result['Attributes']['Enabled'])

    {

        // sns application 의 endpoint 삭제

        $param = ['EndpointArn'=>$sns_endpoint_arn];

        $sns_client = AWS::createClient('sns');

        $sns_client->deleteEndpoint($param);


        // 전체회원topic의 subscription 삭제

        $param = ['SubscriptionArn'=>$sns_subscription_arn];

        $sns_client = AWS::createClient('sns');

        $sns_client->unsubscribe($param);


        // 우리디비에서 삭제

        update ...

    }

}



//------------------------------------------------------------------------------

// 제한사항

//------------------------------------------------------------------------------

topic 최대 갯수 : 100,000 개

topic 당 subscription 최대 갯수 : 12,500,000 개


반응형
Posted by 돌비
,