duanji1026 2018-01-28 23:00
浏览 84

限速PHP功能

I have a php function which gets called when someone visits POST www.example.com/webhook. However, the external service which I cannot control, sometimes calls this url twice in rapid succession, messing with my logic since the webhook persists stuff in the database which takes a few ms to complete.

In other words, when the second request comes in (which can not be ignored), the first request is likely not completed yet however I need this to be completed in the order it came in.

So I've created a little hack in Laravel which should "throttle" the execution with 5 seconds in between. It seems to work most of the time. However an error in my code or some other oversight, does not make this solution work everytime.

function myWebhook() {
    // Check if cache value (defaults to 0) and compare with current time.
    while(Cache::get('g2a_webhook_timestamp', 0) + 5 > Carbon::now()->timestamp) {
        // Postpone execution.
        sleep(1);
    }
    // Create a cache value (file storage) that stores the current 
    Cache::put('g2a_webhook_timestamp', Carbon::now()->timestamp, 1);
    // Execute rest of code ...
}

Anyone perhaps got a watertight solution for this issue?

  • 写回答

1条回答 默认 最新

  • doushouj966020 2018-01-28 23:38
    关注

    You have essentially designed your own simplified queue system which is the right approach but you can make use of the native Laravel queue to have a more robust solution to your problem.

    1. Define a job, e.g: ProcessWebhook
    2. When a POST request is received to /webhook queue the job

    The laravel queue worker will process one job at a time[1] in the order they're received, ensuring that no matter how many requests are received, they'll be processed one by one and in order.

    The implementation of this would look something like this:

    1. Create a new Job, e.g: php artisan make:job ProcessWebhook
    2. Move your webhook processing code into the handle method of the job, e.g:

      public function __construct($data)
      {
          $this->data = $data;
      }
      
      public function handle()
      {
          Model::where('x', 'y')->update([
              'field' => $this->data->newValue
          ]);
      }
      
    3. Modify your Webhook controller to dispatch a new job when a POST request is received, e.g:

      public function webhook(Request $request)
      {
          $data = $request->getContent();
          ProcessWebhook::dispatch($data);
      }
      
    4. Start your queue worker, php artisan queue:work, which will run in the background processing jobs in the order they arrive, one at a time.

    That's it, a maintainable solution to processing webhooks in order, one-by-one. You can read the Queue documentation to find out more about the functionality available, including retrying failed jobs which can be very useful.

    [1] Laravel will process one job at a time per worker. You can add more workers to improve queue throughput for other use cases but in this situation you'd just want to use one worker.

    评论

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题