1

I am using Twilio functions and Programable SMS to send SMS Messages to a list of numbers form my iOS App. There are just over 100 mobile numbers (113 on the time of this error) in the list. Most of these messages send but then the function says that it timed out after 502ms.

I am using the example code from Twilio to send to group messages (that I have copied below) and making a URLSession request from my iOS app.

Is there a way that I can fix this issue so that I can send to this fairly large list of phone numbers or make the function run for longer?

Thank you very much for your help. Tom

Request:

let messagesPhoneNumberString = [+447987654321abc,+447123789456def,+447123456789ghi]
"https://myfunction.twil.io/send-messages?phoneAndID=\(messagesPhoneNumberString)&globalID=\(current globalID)"

My Twilio Function Code:

exports.handler = function(context, event, callback) {

    let phoneAndIDString = event['phoneAndID'];
    let globalID String = event['globalID'];
    let numbersArray = phoneAndIDString.split(",");

Promise.all(
  numbersArray(number => {

      let phoneNumberSplit = "+" + number.slice(1, 13);
      let idSplit = number.slice(13);

      console.log('Send to number: ' + phoneNumberSplit + ' - with ID: ' + idSplit);

    return context.getTwilioClient().messages.create({
      to: phoneNumberSplit,
      from: 'Example',
      body: 'Hello World: ' + idSplit
    });
  })
)
  .then(messages => {
    console.log('Messages sent!');
    callback(null, response);
  })
  .catch(err => console.error(err));
    };
Tom Coomer
  • 6,227
  • 12
  • 45
  • 82

2 Answers2

1

Twilio developer evangelist here.

Twilio Functions has a timeout of 5 seconds, so it is likely not the best idea to use a Twilio Function to send that many messages in one go.

You have some options though.

If you are sending all those numbers the same message then you could use the Twilio Notify passthrough API. Check out the details in this blog post about sending mass messages with Node.js.

Otherwise, if you have to send different messages then you could split up the numbers into batches and use the same function multiple times.

Finally, you could use a different platform to send the messages that doesn't have a 5 second limit.

philnash
  • 70,667
  • 10
  • 60
  • 88
  • Hello, the messages that I am trying to sent are slightly different for each number. If I use the method of splitting the numbers in to batches, do I need to wait a certain length of time before calling the function twice or can I make the requests one straight after another? Thank you – Tom Coomer Jul 15 '19 at 07:32
  • I have just tried the 'split up the numbers into batches and use the same function multiple times' suggestion and had a higher success rate but still experienced the time out message for some of the requests (not all) with batches of 15 numbers at at time. Any suggestions? Is it better to send a single number and message at a time and make the request 113 times (1 for each phone number)? Thanks – Tom Coomer Jul 15 '19 at 15:56
  • 1
    Yeah, one per function is the highest chance of success. Alex's answer might be worth trying. – philnash Jul 16 '19 at 01:37
0

In addition to the options provided in Phil's answer you could use recursion.

You could trigger the process from your app and pass all numbers in the initial function call just like you do now.

Then, the idea is to send just one message per function call and let the Twilio function call itself after it receives the response from .create(). This means no concurent calls to send messages, messages are sent one after another though the order in which they are received is not necessary the order in which the numbers are passed in the query string.

You'll need to add axios in the function dependencies configuration (https://www.twilio.com/console/runtime/functions/configure).

Axios is used to make the HTTP request to the function from within the function.

Each function run, tests for the stop condition which happens when the phone numbers query string length is zero. Then, uses .shift() to remove the first element from the numbers array to work with it. The remaining array is passed to the next function call.

This is the code I've tried, and it worked for me, but you'll have to change (the 11 length on .slice() method) for +44 because I've tested with US numbers +1 which are shorter in length.



exports.handler = function(context, event, callback) {
  const axios = require("axios");

  let phoneAndIDString = event["phoneAndID"].trim();
  console.log(phoneAndIDString);

  let globalIDString = event["globalID"].trim();

  // stop condition for recursive call
  if (phoneAndIDString.length === 0) {
    return callback(null, true);
  }

  let numbersArray = phoneAndIDString.split(",");
  console.log(numbersArray);

  // take the first item of array
  let number = numbersArray.shift();
  console.log(number);

  // the remaining array will be passed to the next function call
  phoneAndIDString = numbersArray.join();
  console.log(phoneAndIDString);

  let phoneNumberSplit = "+" + number.slice(0, 11);
  let idSplit = number.slice(11);
  console.log("Send to number: " + phoneNumberSplit + " - with ID: " + idSplit);

  context
    .getTwilioClient()
    .messages.create({
      to: phoneNumberSplit,
      from: "+17775553333",
      body: "Hello World: " + idSplit
    })
    .then(msg => {
      console.log("Message sent: " + msg.sid);
      axios
        .get(
          "https://foo-bar-1234.twil.io/send-messages?globalID=baz&phoneAndID=" +
            phoneAndIDString
        )
        .then(function(response) {
          // handle success
          console.log(response.status);
          return callback(null, true);
        })
        .catch(function(err) {
          // handle error
          console.error(err);
        });
    })
    .catch(function(err) {
      console.error(err);
    });
};


Try to go step by step with it while testing, console log things and then return early with return callback(null, true) as you go from top to bottom so you make sure you don't go in a loop.
Alex Baban
  • 11,312
  • 4
  • 30
  • 44