1

我正在使用 AWS SNS 发送推送通知,现在我正在使用发送特定设备publish的方法。我的要求是在 30 秒内向数千名会员发送推送。当我使用发布方法时,发送 1000 个用户需要 5 分钟。我已经读过它一次发送多个成员,但我的场景是我想向特定用户发送推送,而不是所有主题用户。aws-php-sdktopic

例如,我在一个主题中注册了 10,000 个成员,但有时我会从这 10,000 个成员中发送 9000 个,有时是 1000 个成员。

因此,任何人都知道如何使用主题发送推送,但仅限特定成员。

我还想另一种情况,每次我创建新主题并注册该主题的成员,然后向他发送消息然后删除topic,但是每次注册成员时也需要时间。因此,如果您有一次注册多个成员的想法,那么它对我也有帮助。

以下是我当前发送推送的代码。

    $arn = "user arn";
    $sns = new Aws\Sns\SnsClient(array(
                    'version' => 'latest',
                    'key' => my_aws_key,
                    'secret' => aws_secret,
                    'region' => region,
                    'profile' => profile_name,
                    'debug' => false,
                    'http' => array('verify' => false)
                ));
$appArn = "application arn";

$sns->publish(array('Message' => '{ "GCM": "{\"data\": { \"message\": \" This is my message \"} }"}',
                     'MessageStructure' => 'json',
                     'TargetArn' => $arn
                        ));
4

2 回答 2

2

我建议使用publishAsync()方法。

$userArnCollection = array(
    'arn:XXX',
    'arn:YYY',
    'arn:ZZZ',
);
$sns = new Aws\Sns\SnsClient(array(
    'version' => 'latest',
    'key'     => my_aws_key,
    'secret'  => aws_secret,
    'region'  => region,
    'profile' => profile_name,
    'debug'   => false,
    'http'    => array('verify' => false)
));

foreach ($userArnCollection as $userArn) {
    $sns->publishAsync(array(
        'Message'          => '{ "GCM": "{\"data\": { \"message\": \" This is my message \"} }"}',
        'MessageStructure' => 'json',
        'TargetArn'        => $userArn
    ));
}

编辑

承诺处理示例

$userArnCollection = array(
    'arn:XXX',
    'arn:YYY',
    'arn:ZZZ',
);
$sns = new Aws\Sns\SnsClient(array(
    'version' => 'latest',
    'key'     => my_aws_key,
    'secret'  => aws_secret,
    'region'  => region,
    'profile' => profile_name,
    'debug'   => false,
    'http'    => array('verify' => false)
));

$promises = array();
foreach ($userArnCollection as $userArn) {
    $promises[] = $sns->publishAsync(array(
        'Message'          => '{ "GCM": "{\"data\": { \"message\": \" This is my message \"} }"}',
        'MessageStructure' => 'json',
        'TargetArn'        => $userArn
    ));
}

$results = \GuzzleHttp\Promise\unwrap($promises);
于 2017-06-26T06:55:25.407 回答
2

在尝试了许多解决方案之后,我能够在一分钟内发送数千条通知,在这里我展示了我是如何做到的,我已经完成了php multicurl功能,所以我执行多个并行进程并且所有进程同时发送通知。

定义多卷曲并准备 URL 以发送通知

假设我有 5,000 个成员,并且我有它的令牌和其他成员详细信息的数组,$device_type_ids_arr 我是 500 个成员中所有成员的一部分,所以每次 curl 执行它都会向 500 个成员发送通知

$_datas = array_chunk($device_type_ids_arr, 500);
/*initialise multi curl*/
$mh = curl_multi_init();
$handles = array();
/* Perform loop for each 500 members batch */
foreach ($_datas as $batchPart) {
    $ch = curl_init();
    $postData['devices'] = $batchPart;
    $postData['push_content'] = $push_content;
    $data_string = json_encode($postData);
    curl_setopt($ch, CURLOPT_URL, base_url() . "EmailPipe/sendNotification/"); //your URL to call amazon service (Explain below)
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_USERAGENT, 'User-Agent: curl/7.39.0');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length:' . strlen($data_string))
    );
    curl_multi_add_handle($mh, $ch);
    $handles[] = $ch;
}
// execute requests and poll periodically until all have completed
$isRunning = null;
do {
    curl_multi_exec($mh, $isRunning);
} while ($isRunning > 0);

/* Once all execution are complete remove curl handler */
foreach ($handles as $ch) {
    curl_multi_remove_handle($mh, $ch);
}
/* Close multi curl */
curl_multi_close($mh);

curl接收请求并发送通知的函数

function sendCurlSignal() {
    require_once APPPATH . 'libraries/aws-sdk/aws-autoloader.php';
    $pipeArr = json_decode(file_get_contents('php://input'), true);
    $push_content = $pipeArr["push_content"];
    $device_id_arr = $pipeArr["devices"];
    $sns = new Aws\Sns\SnsClient(array(
        'version' => 'latest',
        'key' => "Amazon key",
        'secret' => "Amazon secret",
        'region' => "region like eu-west-1",
        'profile' => "Amazon account user",
        'debug' => false,
        'http' => array('verify' => false)
    ));
    $appArn = "SNS application arn";
    $promises = $results = $retArr = array();

    foreach ($device_id_arr as $key => $device_detail) {
        $arn = $device_detail['arn']; /* SNS ARN of each device */
        $token = $device_detail['token_id']; /* Registered token */
        $userid = $device_detail['member_id'];
        /* If you don't have arn then add arn for specific token in amazon */
        if (empty($arn)) {
            try {
                $updatedArn = $sns->createPlatformEndpoint(array('PlatformApplicationArn' => $appArn, 'Token' => $token));
                $arn = $newArn = isset($updatedArn['EndpointArn']) ? $updatedArn['EndpointArn'] : "";
                //update member detail with new arn
                if ($newArn != "" && $userid != "" && $token != "") {
                    /* You can update arn into database for this member */
                }
            } catch (Exception $e) {
                /* Get error if any */
                $errorMsg = $e->getMessage();
                $newFile = fopen("error_arn_fail.txt", "a+");
                fwrite($newFile, "Member Id:" . $userid . "\r\nToken:" . $token . "\r\n" . $errorMsg . "\r\n");
                fclose($newFile);
            }
        }
        if (!empty($arn)) {
            try {
                $promises[$userid] = $sns->publishAsync(array(
                    'Message' => '{ "GCM": "{\"data\": { \"message\": \"' . $push_content . '\" } }"}',
                    'MessageStructure' => 'json',
                    'TargetArn' => $arn
                ));
                $promises[$userid]->arn = $arn;
                $promises[$userid]->token = $token;
            } catch (Exception $e) {
                $errorMsg = $e->getMessage();
                $newFile = fopen("error_async_fail_signal.txt", "a+");
                fwrite($newFile, $errorMsg . "\r\n");
                fclose($newFile);
            }
        }
    }
    /* Broadcast push notification */
    $results = \GuzzleHttp\Promise\settle($promises)->wait(TRUE);

    /* if you want to get result of broadcast and sent message id then do following */
    foreach ($results as $key => $value) {
        if (isset($value['reason'])) {
            /* Reason come in case of fail */
            $message = $value['reason']->getMessage();
            $token = (isset($promises[$key]->token)) ? $promises[$key]->token : "";
            $arn = (isset($promises[$key]->arn)) ? $promises[$key]->arn : "";
            if (empty($arn) || empty($token) || empty($key)) {
                $newFile = fopen("error_empty_detail_result.txt", "a+");
                fwrite($newFile, "Member Id:" . $key . "\r\nArn:" . $arn . "\r\nToken:" . $token . "\r\n");
                fclose($newFile);
            }
            /* Handle error */
            if (strpos($message, "Endpoint is disabled") !== false && $token != "" && $arn != "") {
                try {
                    $res = $sns->setEndpointAttributes(array(
                        'Attributes' => array("Token" => $token, "Enabled" => "true"),
                        'EndpointArn' => $arn
                    ));
                } catch (Exception $e) {
                    $errorMsg = $e->getMessage();
                    $newFile = fopen("error_endpoint_disable.txt", "a+");
                    fwrite($newFile, "Member Id:" . $key . "\r\nArn:" . $arn . "\r\nToken:" . $token . "\r\n" . $errorMsg . "\r\n");
                    fclose($newFile);
                }
            }
            if (strpos($message, "No endpoint found for the target arn specified") !== false && $token != "") {
                try {
                    $updatedArn = $sns->createPlatformEndpoint(array('PlatformApplicationArn' => $appArn, 'Token' => $token));
                    $arn = $newArn = isset($updatedArn['EndpointArn']) ? $updatedArn['EndpointArn'] : "";
                    //update member detail with new arn
                    if ($newArn != "" && !empty($key) && $token != "") {
                        /* You can update arn into database for this member */
                    }
                } catch (Exception $e) {
                    $errorMsg = $e->getMessage();
                    $newFile = fopen("error_arn_fail.txt", "a+");
                    fwrite($newFile, "Member Id:" . $key . "\r\nToken:" . $token . "\r\n" . $errorMsg . "\r\n");
                    fclose($newFile);
                }
            }
            /* After handle error resed notification to this users */
            if (!empty($arn)) {
                try {
                    $publishRes = $sns->publish(array(
                        'Message' => '{ "GCM": "{\"data\": { \"message\": \"' . $push_content . '\" } }"}',
                        'MessageStructure' => 'json',
                        'TargetArn' => $arn
                    ));
                    $retArr[$key] = $publishRes->get("MessageId");
                } catch (Exception $e) {
                    $errorMsg = $e->getMessage();
                    $newFile = fopen("error_push_not_sent.txt", "a+");
                    fwrite($newFile, "Member Id:" . $key . "\r\nARN:" . $arn . "\r\nToken:" . $token . "\r\n" . $errorMsg . "\r\n");
                    fclose($newFile);
                }
            }
        } else {
            $retArr[$key] = $results[$key]['value']->get("MessageId");
        }
    }

    /* All member data get into one array to perform database operation */
    if (isset($retArr) && !empty($retArr)) {
        /* in $retArr you get each member amazon message id */
    }
}
于 2017-11-03T10:54:16.343 回答