Discord机器人无法保留字符串值,Heroku部署后次日重置问题咨询
问题根源:Heroku Dyno 重启导致内存数据丢失
这绝对不是你的代码逻辑问题,问题出在Heroku Dyno的运行机制上。
为什么swingsMessage会被重置?
你现在把swingsMessage存在机器人进程的内存里,但Heroku的免费Dyno有几个特性会导致进程重启:
- 免费Dyno每天会自动休眠6小时,唤醒时会完全重启你的机器人进程
- Heroku会定期对所有Dyno进行系统维护或重启(不管免费还是付费版)
- 当你的应用超过30分钟没有收到请求时,免费Dyno也会进入休眠,再次被触发时重启进程
每次重启都会重新执行你的代码,内存里的swingsMessage自然会被重置为初始值"Update me"。
解决办法:用持久化存储保存数据
要搞定这个问题,你得把swingsMessage的内容存到持久化介质里,而不是依赖进程内存。这里给你两个适合Heroku环境的简单方案:
方案1:用Heroku Redis(轻量键值存储)
Heroku提供免费的Redis插件,非常适合存储这种简单的键值对数据。步骤如下:
- 先在Heroku控制台给你的应用添加Redis插件
- 安装
redis依赖:pip install redis - 修改代码如下:
import discord from discord.ext import commands import redis import os # 从Heroku环境变量获取Redis连接地址 r = redis.from_url(os.environ.get("REDIS_URL")) # 初始化默认值(如果Redis里还没有这个键) if not r.exists("swings_message"): r.set("swings_message", "Update me") client = commands.Bot(command_prefix = "!") @client.command() async def swings(ctx): # 从Redis读取数据,注意转成字符串 swingsMessage = r.get("swings_message").decode('utf-8') await ctx.send(swingsMessage) @client.command() async def update(ctx,*,message): if str(ctx.message.author) == "buysellshort#9420": r.set("swings_message", message) await ctx.send("内容已成功更新!") # 记得从环境变量读取Discord Token,不要硬编码 client.run(os.environ.get("DISCORD_TOKEN"))
方案2:用Heroku PostgreSQL(更适合扩展)
如果你的机器人以后要加更多功能,PostgreSQL会是更稳定的选择。步骤如下:
- 在Heroku控制台给应用添加PostgreSQL插件
- 安装
psycopg2-binary依赖:pip install psycopg2-binary - 修改代码如下:
import discord from discord.ext import commands import psycopg2 import os # 从Heroku环境变量获取数据库连接地址 DATABASE_URL = os.environ.get("DATABASE_URL") conn = psycopg2.connect(DATABASE_URL) c = conn.cursor() # 创建存储表(第一次运行时自动创建) c.execute('''CREATE TABLE IF NOT EXISTS swings_message (id SERIAL PRIMARY KEY, content TEXT NOT NULL)''') # 插入初始默认值(如果表为空) c.execute('SELECT content FROM swings_message') result = c.fetchone() if not result: c.execute('INSERT INTO swings_message (content) VALUES (%s)', ("Update me",)) conn.commit() client = commands.Bot(command_prefix = "!") @client.command() async def swings(ctx): c.execute('SELECT content FROM swings_message LIMIT 1') swingsMessage = c.fetchone()[0] await ctx.send(swingsMessage) @client.command() async def update(ctx,*,message): if str(ctx.message.author) == "buysellshort#9420": c.execute('UPDATE swings_message SET content = %s WHERE id = 1', (message,)) conn.commit() await ctx.send("内容已更新!") client.run(os.environ.get("DISCORD_TOKEN"))
额外提醒
- 不要在Heroku上用SQLite!Heroku的文件系统是临时的,每次重启都会重置到部署时的状态,SQLite文件里的数据会丢失。
- 记得把Discord Token和数据库连接信息放到Heroku的环境变量里,不要硬编码到代码里,避免泄露敏感信息。
内容的提问来源于stack exchange,提问作者user5428151
相关产品推荐
相关产品推荐

