今天我再次遇到这个玄学的事情:当我直接运行程序,运行失败;当我调试运行程序,运行成功。

我通过在程序中插入打印语句来观察程序的状态。好一番功夫才发现,直接运行程序时加载的配置信息是旧的,而调试运行时程序加载的配置信息是新的(所以我才一直发现不了)。

程序中会用到的敏感信息,如用户名和密码被我保存在项目根目录下的.env文件中,程序启动时从文件加载信息到settings对象,用到的时候取settings对象的指定成员变量。代码如下:

from typing import Optional
from pydantic import PostgresDsn, HttpUrl, Field
from pydantic_settings import BaseSettings, SettingsConfigDict
 
class Settings(BaseSettings):
    # Bitcoin Node Settings
    bitcoin_rpc_url: HttpUrl = Field(default="http://localhost:8332")
    bitcoin_rpc_user: str
    bitcoin_rpc_password: str
    
    # Database Settings
    database_url: PostgresDsn
    
    # Analysis Settings
    min_whale_balance: float = Field(default=1000.0)
    block_batch_size: int = Field(default=100)
    max_workers: int = Field(default=4)
    
    # Logging Settings
    log_level: str = Field(default="INFO")
    metrics_enabled: bool = Field(default=True)
    
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding='utf-8',
        case_sensitive=False,
        extra='ignore'  # 添加这行来忽略额外的输入
    )
    
if __name__ == '__main__':
    s = Settings()
    print(s.bitcoin_rpc_user)
    print(s.bitcoin_rpc_password)

我修改了.env中保存的信息,但是,这些信息已经被缓存到了环境变量中,Pydantic 加载配置的优先级是: 系统环境变量 > .env 文件,所以在我直接运行程序时加载的就是旧的信息。

直接读取环境变量信息,可以发现是旧信息:

if __name__ == '__main__':
    import os
    print(os.getcwd())
    print(os.environ.get('BITCOIN_RPC_USER'))

而调试程序时,程序在一个新的 shell 环境中运行,会重新加载.env中的信息,所以程序运行正常。

解决办法:开一个新的 shell 来运行程序。