有时Twilio SMS和Whatsapp逻辑在Vercel生产环境中使用Next.js API路由时不会在无服务器函数中触发

koaltpgm  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(94)

这是NextJS API路由的代码,它在本地环境下工作。

export default async function handler(request, response) {
  const accountSid = process.env.TWILIO_ACCOUNT_SID;
  const authToken = process.env.TWILIO_AUTH_TOKEN;
  const client = require('twilio')(accountSid, authToken);
  await connectMongo();
  const yesterday = subDays(new Date(), 1); 
  const pendingReminders = await Reminder.find({
    reminderSent: false,
    eventCanceled: false,
    reminderDate: {
      $gte: yesterday, // Greater than or equal to yesterday
      $lte: new Date(), // Less than or equal to the current time
    },
  })
  const currentDate = new Date();
  const currentMonth = currentDate.getMonth() + 1; // Adding 1 because months are zero-based
  const currentYear = currentDate.getFullYear();

  console.log('pending', pendingReminders)

  // TODO use Promise.all to handle all in paralell
  for (let i = 0; i < pendingReminders.length; i++) {
    const reminder = pendingReminders[i];
    let monthlyCount = await ReminderMonthlyCount.findOne({
      userId: reminder.userId,
      month: currentMonth,
      year: currentYear
    });
    if(!monthlyCount) {
      monthlyCount = await ReminderMonthlyCount.create({
        userId: reminder.userId,
        month: currentMonth,
        year: currentYear
      })
    }

    if(monthlyCount.count < 20) {
      let settings = await Settings.findOne({userId: reminder.userId})
      if(!settings) {
        settings = await Settings.create({userId: reminder.userId})
      }
      console.log(`Sending message to ${reminder.phoneNumber} from ${reminder.userId}. Scheduled for ${reminder.reminderDate}. Now it is ${new Date()}`);
      client.messages
      .create({
         from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`,
         // Whatsapp templates must be approved before on https://console.twilio.com/us1/develop/sms/senders/whatsapp-templates
         // TODO Not working right now
         body: replaceValues(settings?.reminderMessage, [settings?.personalOrCompanyName || 'us', format(new Date(reminder.reminderDate), "eeee 'at' h:mma"), `${process.env.NEXT_PUBLIC_WEB_URL}appointment/cancel/${reminder['_id']}`]),
         to: `whatsapp:${reminder.phoneNumber}`
       })
      .then(async message => {
        console.log(`${message.sid} message sent to ${reminder.phoneNumber} from ${reminder.userId}. Scheduled for ${reminder.reminderDate}. Now it is ${new Date()}`);
        monthlyCount.count = monthlyCount.count + 1
        reminder.reminderSent = true

        await monthlyCount.save()
        await reminder.save()
      });
    }
  }
  response.status(200).json({ok: true});
}

问题是,当我将它部署到Vercel时,它的行为不稳定。有时候能传达信息有时候不能。它不会抛出错误或任何东西。它只返回200 ok

bejyjqdl

bejyjqdl1#

我认为在promise解析之前,发送的消息和结束的API调用之间可能存在竞争条件。
为了解决这个问题,你必须从promise切换到promise/await,这样你就知道promise和代码在从函数返回之前已经完成了。
代码重构建议:

export default async function handler(request, response) {
  const accountSid = process.env.TWILIO_ACCOUNT_SID;
  const authToken = process.env.TWILIO_AUTH_TOKEN;
  const client = require('twilio')(accountSid, authToken);
  await connectMongo();
  const yesterday = subDays(new Date(), 1); 
  const pendingReminders = await Reminder.find({
    reminderSent: false,
    eventCanceled: false,
    reminderDate: {
      $gte: yesterday, // Greater than or equal to yesterday
      $lte: new Date(), // Less than or equal to the current time
    },
  })
  const currentDate = new Date();
  const currentMonth = currentDate.getMonth() + 1; // Adding 1 because months are zero-based
  const currentYear = currentDate.getFullYear();

  console.log('pending', pendingReminders)

  // TODO use Promise.all to handle all in paralell
  for (let i = 0; i < pendingReminders.length; i++) {
    const reminder = pendingReminders[i];
    let monthlyCount = await ReminderMonthlyCount.findOne({
      userId: reminder.userId,
      month: currentMonth,
      year: currentYear
    });
    if(!monthlyCount) {
      monthlyCount = await ReminderMonthlyCount.create({
        userId: reminder.userId,
        month: currentMonth,
        year: currentYear
      })
    }

    if(monthlyCount.count < 20) {
      let settings = await Settings.findOne({userId: reminder.userId})
      if(!settings) {
        settings = await Settings.create({userId: reminder.userId})
      }
      try {
        console.log(`Sending message to ${reminder.phoneNumber} from ${reminder.userId}. Scheduled for ${reminder.reminderDate}. Now it is ${new Date()}`);
        const message = await client.messages.create({
          from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`,
          // Whatsapp templates must be approved before on https://console.twilio.com/us1/develop/sms/senders/whatsapp-templates
          body: replaceValues(settings?.reminderMessage, [settings?.personalOrCompanyName || 'us', format(new Date(reminder.reminderDate), "eeee 'at' h:mma"), `${process.env.NEXT_PUBLIC_WEB_URL}app/appointment/cancel/${reminder['_id']}`]),
          to: `whatsapp:${reminder.phoneNumber}`
        })

        console.log(`${message.sid} message sent to ${reminder.phoneNumber} from ${reminder.userId}. Scheduled for ${reminder.reminderDate}. Now it is ${new Date()}`);
        monthlyCount.count = monthlyCount.count + 1
        reminder.reminderSent = true

        await monthlyCount.save()
        await reminder.save()

      } catch(err) {
        console.log('Twilio Client error: ', err?.message || err)
      }
    }
  }
  response.status(200).json({ok: true});
}

相关问题