| name | context-usage |
| description | Guide for using genies_context application context management. Use when initializing global context, managing database connections, configuring cache services, handling cross-service authentication tokens, or integrating K8s health status in Genies projects. |
Context Module (genies_context)
Overview
genies_context 是 Genies 框架的应用上下文管理库,提供全局上下文单例、数据库连接池、缓存服务和 JWT 认证中间件。使用 lazy_static 模式实现全局访问。
核心特性:
- 全局上下文单例(CONTEXT)
- 多数据库支持(MySQL、PostgreSQL、SQLite、MSSQL、Oracle、TDengine)
- 数据库连接池(RBatis,自动选择驱动)
- Redis 缓存服务
- Keycloak JWT 验证
- 跨服务 Token 管理(REMOTE_TOKEN)
- K8s 健康探针状态(SERVICE_STATUS)
- Salvo 认证中间件(salvo_auth)
Architecture
应用启动 → CONTEXT (lazy_static) → init_database() → 就绪
│
├── ApplicationContext::new()
│ ├── ApplicationConfig (./application.yml)
│ ├── Keycloak Keys (异步获取)
│ ├── CacheService (Redis)
│ └── Snowflake ID 生成器 (worker_id 解析)
│
└── RBatis (根据 URL scheme 自动选择驱动)
核心组件:
ApplicationContext - 主上下文结构(config, rbatis, cache_service, keycloak_keys)
CONTEXT - 全局单例
REMOTE_TOKEN - 跨服务 Token(Mutex)
SERVICE_STATUS - K8s 探针状态(Mutex)
init_database() - 数据库初始化(自动选择驱动,Once 保证幂等)
init_mysql() - 已废弃,init_database 的别名
salvo_auth - JWT 认证中间件
checked_token / is_white_list_api - 认证辅助函数
Quick Start
1. Dependencies
[dependencies]
genies_context = { workspace = true }
genies_config = { workspace = true }
genies_cache = { workspace = true }
genies_core = { workspace = true }
rbatis = "4.x"
2. Initialize Database
use genies::context::CONTEXT;
#[tokio::main]
async fn main() {
CONTEXT.init_database().await;
println!("数据库已连接: {:?}", CONTEXT.rbatis.get_pool().unwrap().state().await);
}
3. Use Database
use genies::context::CONTEXT;
use rbatis::executor::Executor;
pub async fn query_users() -> Vec<User> {
User::select_all(&CONTEXT.rbatis).await.unwrap()
}
pub async fn create_user(user: &User) {
let mut tx = CONTEXT.rbatis.acquire_begin().await.unwrap();
User::insert(&mut tx, user).await.unwrap();
tx.commit().await.unwrap();
}
4. Use Cache
use genies::context::CONTEXT;
CONTEXT.cache_service.set_string("key", "value").await?;
let value = CONTEXT.cache_service.get_string("key").await?;
CONTEXT.redis_save_service.set_string("key", "data").await?;
5. Configure Auth Middleware
use genies::context::auth::salvo_auth;
use salvo::prelude::*;
let router = Router::new()
.hoop(salvo_auth)
.push(Router::with_path("/api/users").get(get_users));
API Reference
ApplicationContext
pub struct ApplicationContext {
pub config: ApplicationConfig,
pub rbatis: RBatis,
pub cache_service: CacheService,
pub redis_save_service: CacheService,
pub keycloak_keys: Keys,
}
impl ApplicationContext {
pub async fn init_database(&self);
#[deprecated]
pub async fn init_mysql(&self);
pub fn new() -> Self;
}
Global Singletons
lazy_static! {
pub static ref CONTEXT: ApplicationContext = ApplicationContext::default();
pub static ref REMOTE_TOKEN: Mutex<RemoteToken> = Mutex::new(RemoteToken::new());
pub static ref SERVICE_STATUS: Mutex<HashMap<String, bool>> = Mutex::new({
let mut map = HashMap::new();
map.insert("readinessProbe".to_string(), true);
map.insert("livenessProbe".to_string(), true);
map
});
}
RemoteToken
pub struct RemoteToken {
pub access_token: String,
}
impl RemoteToken {
pub fn new() -> Self;
}
Auth Functions
pub fn is_white_list_api(context: &ApplicationContext, path: &str) -> bool;
pub async fn checked_token(
context: &ApplicationContext,
token: &str,
path: &str,
) -> Result<JWTToken, Error>;
#[handler]
pub async fn salvo_auth(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl);
Configuration
application.yml
server_url: "0.0.0.0:5800"
database_url: "mysql://user:pass@localhost:3306/db"
max_connections: 10
wait_timeout: 30
max_lifetime: 3600
redis_host: "localhost"
redis_port: 6379
keycloak_auth_server_url: "http://localhost:8080"
keycloak_realm: "myrealm"
keycloak_resource: "myapp"
keycloak_credentials_secret: "secret"
white_list_api:
- "/health"
- "/dapr/*"
- "/swagger-ui/*"
Feature Flags
| Feature | 驱动 | URL Scheme |
|---|
mysql(默认) | rbdc-mysql | mysql:// |
postgres | rbdc-pg | postgres://, postgresql:// |
sqlite | rbdc-sqlite | sqlite:// |
mssql | rbdc-mssql | mssql://, sqlserver:// |
oracle | rbdc-oracle | oracle:// |
tdengine | rbdc-tdengine | taos://, taos+ws:// |
all-db | 所有驱动 | 以上所有 |
切换数据库:
[dependencies]
genies = { version = "1.5", default-features = false, features = ["postgres"] }
genies_context = { version = "1.5", default-features = false, features = ["postgres"] }
Auth Middleware Flow
请求 → salvo_auth
│
├── 白名单? → 跳过认证
│
└── 否 → checked_token()
│
├── 有效 → depot.insert("jwtToken") → 继续
└── 无效 → 401 Unauthorized
K8s Health Status
use genies::context::SERVICE_STATUS;
{
let mut status = SERVICE_STATUS.lock().unwrap();
status.insert("readinessProbe".to_string(), false);
}
{
let status = SERVICE_STATUS.lock().unwrap();
let is_alive = *status.get("livenessProbe").unwrap_or(&false);
}
Thread Safety
CONTEXT: lazy_static 单次初始化,字段线程安全
init_database(): Once 保证幂等
REMOTE_TOKEN: Mutex 线程安全
SERVICE_STATUS: Mutex 线程安全
Integration
- genies_auth: 使用
CONTEXT.rbatis 存储策略,salvo_auth 进行 JWT 验证
- genies_ddd: 使用
CONTEXT.rbatis 发布事件
- genies_dapr: 使用
CONTEXT.rbatis 事务管理
- genies_config: 提供
ApplicationConfig
Key Files
Snowflake Worker ID Resolution
ApplicationContext::new() automatically initializes the Snowflake ID generator by resolving a unique worker_id.
Resolution Priority
-
Redis Slot Registration (when cache_type = "redis"):
- Iterates slots 0..1023, uses
SETNX snowflake:slot:{server_name}:{i} with 1-hour TTL
- First successful slot becomes the worker_id
- Background thread renews TTL every 30 minutes using
CONTEXT.cache_service
- Handles both in-runtime and standalone contexts via
Handle::try_current()
-
K8s HOSTNAME: Extracts numeric suffix from HOSTNAME env var (e.g., pod-name-3 → 3), modulo 1024
-
Config File: Uses machine_id from application.yml if set
-
Fallback: Defaults to 1
Configuration
machine_id: 1
After Initialization
Business code can generate IDs via:
let id = genies::next_id();