feat(ids): 实现基于Snowflake的分布式ID生成功能
新增rs-snowflake依赖并实现分布式ID生成工具 在utils模块中添加ids子模块,提供业务ID生成与解析功能 替换原有UUID生成方式为分布式ID生成器
This commit is contained in:
@ -64,6 +64,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
let redis_pool = redis::init_redis().await?;
|
||||
redis::set_redis_pool(redis_pool)?;
|
||||
|
||||
// 初始化分布式ID生成器(读取 ID_MACHINE_ID / ID_NODE_ID)
|
||||
crate::utils::init_from_env();
|
||||
|
||||
// run migrations
|
||||
migration::Migrator::up(&db, None).await.expect("migration up");
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ pub struct CreateRunLogInput {
|
||||
|
||||
pub async fn create(db: &Db, input: CreateRunLogInput) -> anyhow::Result<i64> {
|
||||
let am = flow_run_log::ActiveModel {
|
||||
id: Default::default(),
|
||||
id: Set(crate::utils::generate_flow_run_log_id()),
|
||||
flow_id: Set(input.flow_id),
|
||||
flow_code: Set(input.flow_code),
|
||||
input: Set(input.input),
|
||||
|
||||
@ -98,7 +98,7 @@ pub async fn create(db: &Db, req: FlowCreateReq) -> anyhow::Result<FlowDoc> {
|
||||
let _parsed: FlowDSL = serde_yaml::from_str(yaml).context("invalid flow yaml")?;
|
||||
info!(target: "udmin", "flow.create: yaml parsed ok");
|
||||
}
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let id = crate::utils::generate_flow_id();
|
||||
let name = req
|
||||
.name
|
||||
.clone()
|
||||
|
||||
@ -17,7 +17,7 @@ pub struct CreateLogInput {
|
||||
|
||||
pub async fn create(db: &Db, input: CreateLogInput) -> anyhow::Result<i64> {
|
||||
let am = request_log::ActiveModel {
|
||||
id: Default::default(),
|
||||
id: Set(crate::utils::generate_request_log_id()),
|
||||
path: Set(input.path),
|
||||
method: Set(input.method),
|
||||
request_params: Set(input.request_params),
|
||||
|
||||
83
backend/src/utils/ids.rs
Normal file
83
backend/src/utils/ids.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::sync::Mutex;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
// 采用 rs-snowflake 提供的 SnowflakeIdGenerator
|
||||
// machine_id 与 node_id 取值范围建议 < 32
|
||||
use snowflake::SnowflakeIdGenerator;
|
||||
|
||||
// 全局生成器(按需初始化),以避免重复构造与时序问题
|
||||
static GENERATOR: Lazy<Mutex<SnowflakeIdGenerator>> = Lazy::new(|| {
|
||||
let (machine_id, node_id) = read_ids_from_env();
|
||||
Mutex::new(SnowflakeIdGenerator::new(machine_id, node_id))
|
||||
});
|
||||
|
||||
fn read_ids_from_env() -> (i32, i32) {
|
||||
let machine_id = std::env::var("ID_MACHINE_ID").ok().and_then(|s| s.parse::<i32>().ok()).unwrap_or(1);
|
||||
let node_id = std::env::var("ID_NODE_ID").ok().and_then(|s| s.parse::<i32>().ok()).unwrap_or(1);
|
||||
// 保护:按 0..32 范围裁剪,避免越界(生成器要求 machine_id/node_id < 32)
|
||||
let clamp = |v: i32| if v < 0 { 0 } else if v > 31 { 31 } else { v };
|
||||
(clamp(machine_id), clamp(node_id))
|
||||
}
|
||||
|
||||
/// 可选:在启动时主动初始化并打印日志,便于观测
|
||||
pub fn init_from_env() {
|
||||
let (machine_id, node_id) = read_ids_from_env();
|
||||
// 触发 Lazy 初始化(不获取锁,避免非绑定锁 lint)
|
||||
Lazy::force(&GENERATOR);
|
||||
tracing::info!(target: "udmin", "snowflake init: machine_id={} node_id={}", machine_id, node_id);
|
||||
}
|
||||
|
||||
/// 业务ID生成器(按示例:主业务16位,子业务8位,Snowflake保留低39位 => 共63位,最高符号位为0)
|
||||
pub struct BizIdConfig {
|
||||
pub main_id: u16, // 16 bits
|
||||
pub sub_id: u8, // 8 bits
|
||||
}
|
||||
|
||||
impl BizIdConfig {
|
||||
pub const fn new(main_id: u16, sub_id: u8) -> Self { Self { main_id, sub_id } }
|
||||
}
|
||||
|
||||
/// 生成带业务前缀的分布式ID(返回 i64)
|
||||
pub fn generate_biz_id(cfg: BizIdConfig) -> i64 {
|
||||
let mut g = GENERATOR.lock().expect("gen snowflake id");
|
||||
let base_id = g.real_time_generate();
|
||||
// 只保留低 39 位
|
||||
let snowflake_bits = base_id & ((1i64 << 39) - 1);
|
||||
let main_bits = (cfg.main_id as i64) << (39 + 8);
|
||||
let sub_bits = (cfg.sub_id as i64) << 39;
|
||||
main_bits | sub_bits | snowflake_bits
|
||||
}
|
||||
|
||||
/// 解析业务ID -> (main_id, sub_id, base_id)
|
||||
pub fn parse_biz_id(id: i64) -> (u16, u8, i64) {
|
||||
let main_id = ((id >> (39 + 8)) & 0xFFFF) as u16;
|
||||
let sub_id = ((id >> 39) & 0xFF) as u8;
|
||||
let base_id = id & ((1i64 << 39) - 1);
|
||||
(main_id, sub_id, base_id)
|
||||
}
|
||||
|
||||
// --- 具体业务场景:Flow 使用的一组常量(可按需扩展/调整) ---
|
||||
// 你可以把这些常量提到配置或用枚举维护各业务的 main/sub 编码
|
||||
const FLOW_MAIN_ID: u16 = 1;
|
||||
const FLOW_SUB_ID: u8 = 1;
|
||||
|
||||
/// 生成 Flow 的 ID,返回十进制字符串,便于与原先 string 类型主键兼容
|
||||
pub fn generate_flow_id() -> String {
|
||||
let id = generate_biz_id(BizIdConfig::new(FLOW_MAIN_ID, FLOW_SUB_ID));
|
||||
id.to_string()
|
||||
}
|
||||
|
||||
// --- 日志类 ID 的业务位定义与生成 ---
|
||||
const FLOW_RUN_LOG_MAIN_ID: u16 = 2;
|
||||
const FLOW_RUN_LOG_SUB_ID: u8 = 1;
|
||||
|
||||
pub fn generate_flow_run_log_id() -> i64 {
|
||||
generate_biz_id(BizIdConfig::new(FLOW_RUN_LOG_MAIN_ID, FLOW_RUN_LOG_SUB_ID))
|
||||
}
|
||||
|
||||
const REQUEST_LOG_MAIN_ID: u16 = 3;
|
||||
const REQUEST_LOG_SUB_ID: u8 = 1;
|
||||
|
||||
pub fn generate_request_log_id() -> i64 {
|
||||
generate_biz_id(BizIdConfig::new(REQUEST_LOG_MAIN_ID, REQUEST_LOG_SUB_ID))
|
||||
}
|
||||
@ -1 +1,4 @@
|
||||
pub mod password;
|
||||
pub mod password;
|
||||
pub mod ids;
|
||||
|
||||
pub use ids::{init_from_env, generate_biz_id, parse_biz_id, generate_flow_id, BizIdConfig, generate_flow_run_log_id, generate_request_log_id};
|
||||
Reference in New Issue
Block a user