You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Google Cloud中闲置的Node.js应用持续运行并保留缓存?

解决Google App Engine Node.js应用闲置回收导致缓存丢失的问题

你的核心问题是App Engine标准环境下,实例闲置30分钟后会被自动回收,重启时需要重新加载Google Sheet数据,导致Slack请求响应延迟。以下是针对性的解决方案:

一、优化App Engine自动缩放配置

修改你的app.yaml,添加闲置超时配置,延长实例存活时间:

runtime: nodejs22
entrypoint: node index.js 
instance_class: F1

automatic_scaling:
  min_instances: 1
  min_idle_instances: 1
  max_idle_instances: 1
  min_pending_latency: automatic
  max_pending_latency: automatic
  max_concurrent_requests: 50
  idle_timeout_sec: 86400  # 设置为1天,避免闲置回收(可根据需求调整)

env: standard

handlers:
- url: /_ah/warmup
  script: auto
  login: admin
  secure: always

- url: /.*
  script: auto

readiness_check:
  path: /_ah/health
  check_interval_sec: 5
  timeout_sec: 4
  failure_threshold: 5
  success_threshold: 2

inbound_services:
- warmup 

说明:idle_timeout_sec默认是1800秒(30分钟),延长这个值可以避免实例因闲置被快速回收。

二、处理Warmup请求预加载缓存

当前你的代码没有处理/_ah/warmup路由,导致实例启动时不会自动预加载Sheet数据。添加以下路由到你的Express应用中:

// 处理warmup请求,预加载缓存
app.get('/_ah/warmup', async (req, res) => {
  try {
    await fetchFilteredSheetData();
    console.log('Warmup completed: cache loaded');
    res.status(200).send('Warmed up');
  } catch (error) {
    console.error('Warmup failed:', error);
    res.status(500).send('Warmup failed');
  }
});

// 处理健康检查请求
app.get('/_ah/health', (req, res) => {
  res.status(200).send('Healthy');
});

说明:Warmup请求会在实例启动前触发,提前加载缓存,确保用户请求到达时缓存已经就绪,消除启动延迟。

三、添加心跳机制防止实例闲置

即使设置了min_instances,App Engine仍可能在极端情况下回收实例。添加定时心跳请求,每25分钟向自己的实例发送请求,避免进入闲置状态:

// 在startApp函数中添加心跳任务
cron.schedule('*/25 * * * *', async () => {
  try {
    // 生产环境使用App Engine分配的服务URL,本地测试用localhost
    const appUrl = process.env.GCP_SERVICE_URL || `http://localhost:${port}`;
    await fetch(`${appUrl}/_ah/health`);
    console.log('Heartbeat sent to keep instance alive');
  } catch (error) {
    console.error('Heartbeat request failed:', error);
  }
});

说明:定时请求会让实例保持活跃状态,避免触发闲置回收逻辑。

四、备选方案:缓存持久化到外部存储

如果实例仍不可避免被回收,可以将缓存数据存储到外部服务(如Cloud Memorystore Redis或Firestore),重启时直接从外部加载,比重新读取Google Sheet快得多:

// 示例:使用Redis存储缓存(需先安装redis包)
const redis = require('redis');
const client = redis.createClient({ url: process.env.REDIS_URL });

// 修改fetchFilteredSheetData,将数据存入Redis
async function fetchFilteredSheetData() {
  // ... 原有获取Sheet数据的逻辑 ...

  // 将缓存数据存入Redis,设置过期时间为1天(与定时更新频率匹配)
  await client.setEx('sheet_cache', 86400, JSON.stringify({ cachedData, dataDictionary }));
}

// 启动时优先从Redis加载缓存
async function startApp() {
  console.log("Starting up the app...");
  await client.connect();

  try {
    // 尝试从Redis加载缓存
    const cached = await client.get('sheet_cache');
    if (cached) {
      const { cachedData: redisCached, dataDictionary: redisDict } = JSON.parse(cached);
      cachedData = redisCached;
      dataDictionary = redisDict;
      console.log('Loaded cache from Redis');
    } else {
      // Redis无缓存时,从Sheet加载
      await fetchFilteredSheetData();
      console.log('Loaded cache from Google Sheet');
    }

    // ... 原有定时任务和启动服务器的逻辑 ...
  } catch (error) {
    console.error('Error during startup:', error);
  }
}

说明:外部缓存可以让实例重启后快速恢复缓存状态,无需重新读取整个Sheet。


内容的提问来源于stack exchange,提问作者Jim Burke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:10:08