简体   繁体   English

如何在 node.js 中运行 api 请求 6/8 小时或更长时间?

[英]How to run an api request for 6/8 hours or more in node js?

I have to pull some large amount of data from shopify through api2cart API. I need to pull data for 2/3 years back, which takes hours to pull as we can only pull 250 items per request.我必须通过 api2cart API 从 shopify 提取大量数据。我需要提取 2/3 年前的数据,这需要几个小时才能提取,因为我们每个请求只能提取 250 个项目。 With each response, it provides a key to next 250 data pull and so on.对于每个响应,它都会提供下一个 250 数据拉取的密钥,依此类推。

In my backend, I'm pulling data and saving it in a csv file through fs and then I call the api again for next 250 items.在我的后端,我正在提取数据并通过 fs 将其保存在 csv 文件中,然后我再次调用 api 以获取接下来的 250 个项目。 it works well on my local machine.它在我的本地机器上运行良好。 the process continues untill all the data are fetched.该过程一直持续到获取所有数据为止。 I can pull years of data and it takes about 2-3 hours to pull about 100k/150k data.我可以提取多年的数据,提取大约 100k/150k 数据大约需要 2-3 小时。

Then I set up a NestJS Microservice and deployed on a digital ocean server.然后我设置了一个 NestJS 微服务并部署在数字海洋服务器上。 But when I make an API request for long time, after a few time, server gives me a 504 Gateway timeout Error.但是当我长时间发出 API 请求时,一段时间后,服务器给我一个 504 网关超时错误。

Can't use the setTimeout as there' no limit to this process.不能使用 setTimeout,因为这个过程没有限制。 is there any way to keep pulling data for hours or days?有什么办法可以持续数小时或数天提取数据?

What to do to pull data for hours without any 504 Gateway timeout Error?如何在没有任何 504 网关超时错误的情况下提取数小时的数据?

Very long running requests are in general error-prone.运行时间非常长的请求通常容易出错。 A connection reset could result in restarting the whole process again.连接重置可能会导致再次重新启动整个过程。 Even though this won't fix the underlaying problem you described with digital ocean, I think it's worth you consider a different solution.尽管这不能解决您描述的数字海洋的底层问题,但我认为您值得考虑一个不同的解决方案。 I recommend to split up your heavy, long-running task into many small tasks and use a queue system.我建议将繁重的、长时间运行的任务拆分成许多小任务,并使用队列系统。

Nestjs provides a very good documentation using queues and the bull package. Nestjs 提供了一个非常好的文档使用队列和公牛 package。

I added a basic example, with two solutions:我添加了一个基本示例,有两个解决方案:

Queue consumer队列消费者

shopify.consumer.ts shopify.consumer.ts

import { Processor, Process } from '@nestjs/bull';
import { Job } from 'bull';

@Processor('shopify')
export class ShopifyConsumer {
  constructor(
    private shopifyService: ShopifyService
  ) {}

  @Process('fetch')
  async transcode(job: Job<unknown>) {
    await this.shopifyService.fetch(job.requestKey);
  }
}

Option a) Generate all requests at once and let the queue process them:选项 a) 一次生成所有请求并让队列处理它们:

shopify.service.ts shopify.service.ts

import { Injectable } from '@nestjs/common';
import { Queue } from 'bull';
import { InjectQueue } from '@nestjs/bull';

@Injectable()
export class ShopifyService {
  constructor(
    @InjectQueue('shopify') private shopifyQueue: Queue
  ) {}
    
  generateJobs(requestKeys: string[]) {
    for (const requestKey of requestKeys) {
      await this.shopifyQueue.add('fetch', { 
        requestKey
      });
    }
  }

  fetch(requestKey: string) {
    // Fetch data
    const res = await fetch('...')
  }
}

Option b) Generate a new queue job after every response选项 b) 在每次响应后生成一个新的队列作业

shopify.service.ts shopify.service.ts

import { Injectable } from '@nestjs/common';
import { Queue } from 'bull';
import { InjectQueue } from '@nestjs/bull';

@Injectable()
export class ShopifyService {
  constructor(
    @InjectQueue('shopify') private shopifyQueue: Queue
  ) {}

  fetch(requestKey: string) {
    // Fetch data
    const res = await fetch('...')
    
    // Add next job to queue if more chunks are available
    if (res.nextRequestKey) {
      await this.shopifyQueue.add('fetch', { 
        requestKey: res.nextRequestKey
      })
    }
  }
}

Queues and Bull work well with NestJS, and I would recommend them for these long calls. Queues 和 Bull 与 NestJS 配合得很好,我会推荐它们用于这些长调用。 It is really helpful as you can also retry calls, and add a timeout for failed jobs (to help with 417 errors).这真的很有帮助,因为您还可以重试呼叫,并为失败的作业添加超时(以帮助解决 417 错误)。

import { Injectable } from '@nestjs/common';
import { Queue } from 'bull';
import { InjectQueue } from '@nestjs/bull';

@Injectable()
export class ShopifyService {
  constructor(
    @InjectQueue('shopify') private shopifyQueue: Queue
  ) {}
    
  async generateJobs(requestKeys: string[]) {

    await this.shopifyQueue.addBulk('${QUEUE_NAME}.${JOB_NAME}', { 
      ...jobData //what is needed to make API call
    },
    {
      attempts: 5,
      backoff: 5000,
      //Will try 5 times with backoff
    });
  }
}
    ```

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM