繁体   English   中英

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

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

我必须通过 api2cart API 从 shopify 提取大量数据。我需要提取 2/3 年前的数据,这需要几个小时才能提取,因为我们每个请求只能提取 250 个项目。 对于每个响应,它都会提供下一个 250 数据拉取的密钥,依此类推。

在我的后端,我正在提取数据并通过 fs 将其保存在 csv 文件中,然后我再次调用 api 以获取接下来的 250 个项目。 它在我的本地机器上运行良好。 该过程一直持续到获取所有数据为止。 我可以提取多年的数据,提取大约 100k/150k 数据大约需要 2-3 小时。

然后我设置了一个 NestJS 微服务并部署在数字海洋服务器上。 但是当我长时间发出 API 请求时,一段时间后,服务器给我一个 504 网关超时错误。

不能使用 setTimeout,因为这个过程没有限制。 有什么办法可以持续数小时或数天提取数据?

如何在没有任何 504 网关超时错误的情况下提取数小时的数据?

运行时间非常长的请求通常容易出错。 连接重置可能会导致再次重新启动整个过程。 尽管这不能解决您描述的数字海洋的底层问题,但我认为您值得考虑一个不同的解决方案。 我建议将繁重的、长时间运行的任务拆分成许多小任务,并使用队列系统。

Nestjs 提供了一个非常好的文档使用队列和公牛 package。

我添加了一个基本示例,有两个解决方案:

队列消费者

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);
  }
}

选项 a) 一次生成所有请求并让队列处理它们:

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('...')
  }
}

选项 b) 在每次响应后生成一个新的队列作业

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 和 Bull 与 NestJS 配合得很好,我会推荐它们用于这些长调用。 这真的很有帮助,因为您还可以重试呼叫,并为失败的作业添加超时(以帮助解决 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