使用 Upstash 时,Vercel 上的 Redis 操作在执行后挂起

问题描述 投票:0回答:1

此代码在本地运行没有任何问题,但在部署到 Vercel 上时会挂起。当我在Upstash中查看Redis监控时,发现有时数据插入成功,有时则插入失败。 Vercel 上的日志显示,有时代码会通过await 语句,但有时会卡在await 处。

我使用 Upstash 的 Redis 进行即用即付计划,使用 Vercel 进行 Pro 计划。

我也在使用Upstash的QStash,我也遇到了类似的问题。有时它会成功触发,而有时它会在第一次调用时卡住。所有这些操作在本地运行时都可以正常工作。

import { Redis } from '@upstash/redis'
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
  enableAutoPipelining: true,
  retry: {
    retries: 5,
    backoff: (retryCount) => Math.exp(retryCount) * 50,
  },
})
const result = await Promise.all([
  redis.hset(taskId + '_info', {platform,searchId,collectionId,}),
  redis.rpush(taskId, ...keywords),
  redis.expire(taskId, TASK_EXPIRY_TIME),
  redis.expire(taskId + '_info', TASK_EXPIRY_TIME)
  ]);```
      

我尝试了多种解决方案来解决此问题:

  • 调整Vercel的函数执行时间:我尝试在Vercel的设置中增加函数超时,但这并没有解决挂起的问题。

  • 使用Redis管道:我尝试使用Redis管道将多个命令一起批处理,如下所示:

const pipeline = redis.pipeline();
pipeline.hset(taskId + '_info', { /* data */ });
pipeline.rpush(taskId, ...keywords);
pipeline.expire(taskId, TASK_EXPIRY_TIME);
pipeline.expire(taskId + '_info', TASK_EXPIRY_TIME);
const results = await pipeline.exec();

但是,这种方法在某些情况下仍然会导致相同的挂起行为。

  • 切换到ioredis:我也尝试过使用ioredis库而不是Upstash的Redis客户端,但在无服务器环境中遇到了类似的不一致问题。
typescript next.js redis vercel serverless
1个回答
0
投票

启用自动流水线后,您提供的代码示例实际上是等效的。

您可以尝试以下两件事:

  1. 禁用自动流水线并尝试一一运行命令:
const hsetResult = await redis.hset(taskId + '_info', {platform,searchId,collectionId,})
const rpushResult = await redis.rpush(taskId, ...keywords)
const expireResult = await redis.expire(taskId, TASK_EXPIRY_TIME)
const expireResult2 = await redis.expire(taskId + '_info', TASK_EXPIRY_TIME)

此代码远非理想,因为它会导致多个请求,但可以帮助您调试错误。

  1. 禁用重试。如果问题仍然存在,可能是因为 sdk 出现错误并且在重试时似乎挂起。您可以尝试禁用重试并检查是否有错误。
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
  enableAutoPipelining: true,
  retry: false
})
© www.soinside.com 2019 - 2024. All rights reserved.