diff --git a/public/message/output/sms/tests/message_output_sms_test.php b/public/message/output/sms/tests/message_output_sms_test.php index 454e25da0c3..7c7cea567bf 100644 --- a/public/message/output/sms/tests/message_output_sms_test.php +++ b/public/message/output/sms/tests/message_output_sms_test.php @@ -100,6 +100,7 @@ final class message_output_sms_test extends \advanced_testcase { $this->assertCount(1, $adhoctask); // Now lets run the task and check if SMS is sent. + $this->expectOutputRegex('/SMS send status: gateway_sent/'); $this->run_all_adhoc_tasks(); $message = $manager->get_message(['id' => $message->id]); diff --git a/public/sms/classes/task/send_sms_task.php b/public/sms/classes/task/send_sms_task.php index 952eaf9ce2f..3c84732a325 100644 --- a/public/sms/classes/task/send_sms_task.php +++ b/public/sms/classes/task/send_sms_task.php @@ -18,6 +18,7 @@ namespace core_sms\task; use core\task\adhoc_task; use core_sms\message; +use core_sms\message_status; /** * Ad-hoc task to send an SMS. @@ -39,11 +40,23 @@ class send_sms_task extends adhoc_task { $message = $manager->get_message( filter: ['id' => $smsdata->messageid], ); - $manager->send_message( + $message = $manager->send_message( message: $message, async: false, ); + $status = $message?->status; + $retryfailures = [ + message_status::GATEWAY_FAILED, + message_status::GATEWAY_NOT_AVAILABLE, + ]; + if (in_array($status, $retryfailures)) { + // Only retry if the failure encountered will possibly resolve in subsequent attempts. + mtrace("SMS failed status: {$status?->value} - task will retry"); + throw new \moodle_exception('SMS Gateway encountered a failure'); + } else { + mtrace("SMS send status: " . ($status?->value ?? message_status::UNKNOWN->value)); + } } /** diff --git a/public/sms/gateway/aws/classes/local/service/aws_sns.php b/public/sms/gateway/aws/classes/local/service/aws_sns.php index eed04e14345..4371b71d5ab 100644 --- a/public/sms/gateway/aws/classes/local/service/aws_sns.php +++ b/public/sms/gateway/aws/classes/local/service/aws_sns.php @@ -59,18 +59,19 @@ class aws_sns implements aws_sms_service_provider { $senderid = substr($senderid, 0, 11); try { - // These messages need to be transactional. - $client->SetSMSAttributes([ - 'attributes' => [ - 'DefaultSMSType' => 'Transactional', - 'DefaultSenderID' => $senderid, - ], - ]); - - // Actually send the message. $client->publish([ 'Message' => $messagecontent, 'PhoneNumber' => $phonenumber, + 'MessageAttributes' => [ + 'AWS.SNS.SMS.SenderID' => [ + 'DataType' => 'String', + 'StringValue' => $senderid, + ], + 'AWS.SNS.SMS.SMSType' => [ + 'DataType' => 'String', + 'StringValue' => 'Transactional', + ], + ], ]); return \core_sms\message_status::GATEWAY_SENT; } catch (\Aws\Exception\AwsException $e) { diff --git a/public/sms/tests/manager_test.php b/public/sms/tests/manager_test.php index 320dc9553c5..8f21dff8610 100644 --- a/public/sms/tests/manager_test.php +++ b/public/sms/tests/manager_test.php @@ -465,6 +465,7 @@ final class manager_test extends \advanced_testcase { $this->assertCount(1, $adhoctask); // Now lets run the task and check if SMS is sent. + $this->expectOutputRegex('/SMS send status: gateway_sent/'); $this->run_all_adhoc_tasks(); $message = $manager->get_message(['id' => $message->id]); @@ -551,4 +552,41 @@ final class manager_test extends \advanced_testcase { $this->assertCount(1, $messages); array_walk($messages, fn ($message) => $this->assertInstanceOf(message::class, $message)); } + + /** + * Test async message is resent when gateway is not available. + */ + public function test_resend_when_gateway_not_available(): void { + $this->resetAfterTest(); + + $manager = \core\di::get(\core_sms\manager::class); + + $message = $manager->send( + recipientnumber: '+447123456789', + content: 'Hello, world!', + component: 'core', + messagetype: 'test', + recipientuserid: null, + async: true, + ); + + $messagedbrecords = $manager->get_messages(); + $messages = iterator_to_array($messagedbrecords); + $this->assertCount(1, $messages); + + $adhoctask = \core\task\manager::get_adhoc_tasks(send_sms_task::class); + $this->assertCount(1, $adhoctask); + + try { + $this->expectOutputRegex('/SMS failed status: gateway_not_available - task will retry/'); + $this->run_all_adhoc_tasks(); + $this->fail('Exception expected'); + } catch (\moodle_exception $e) { + $message = $manager->get_message(['id' => $message->id]); + $this->assertEquals(message_status::GATEWAY_NOT_AVAILABLE, $message->status); + + $adhoctask = \core\task\manager::get_adhoc_tasks(send_sms_task::class); + $this->assertCount(1, $adhoctask); + } + } }