5 releases (3 breaking)

0.4.0 May 8, 2022
0.3.0 May 6, 2022
0.2.1 Feb 20, 2017
0.2.0 Feb 20, 2017
0.1.0 Feb 16, 2017

#658 in Encoding

31 downloads per month

MIT license

26KB
496 lines

frostflake

Crates.io

Customizable and thread-safe distributed id generator, like twitter's snowflake.

Simple usage for single generator

use frostflake::{Generator, GeneratorOptions};

let mut generator = Generator::new(GeneratorOptions::default());

let id1 = generator.generate();
let id2 = generator.generate();
let id3 = generator.generate();

Async generator works with tokio

This requires tokio feature.

use frostflake::{GeneratorAsync, GeneratorOptions};

#[tokio::main]
async fn main() {
    let generator = GeneratorAsync::spawn(GeneratorOptions::default());

    let id1 = generator.generate().await.unwrap();
}

GeneratorAsync is Send so that you can pass it to other threads or tasks safely.

use frostflake::{GeneratorAsync, GeneratorOptions};

#[tokio::main]
async fn main() {
    let g = GeneratorAsync::spawn(GeneratorOptions::default());
    for _ in 0..10 {
        let g = g.clone();
        tokio::spawn(async move {
            let id = g.generate().await.unwrap();
        });
    }
}

Multi-threads generator by GeneratorPool

This requires std-thread feature.

use frostflake::{GeneratorPool, GeneratorPoolOptions};
use std::thread;

// create 10 generators
let pool = GeneratorPool::new(10, GeneratorPoolOptions::default());

{
    // pool also can be shared with threads by std::sync::Arc
    let pool = pool.clone();
    thread::spawn(move || {
        let id = pool.generate();
    }).join();
}

Configurations

frostflake is highly configurable.

use frostflake::{Generator, GeneratorOptions};

let opts = GeneratorOptions::default()
    .bits(42, 10, 12)           // 42bit timestamp, 10bit node, 12bit sequence
    .base_ts(1483228800000)     // base time 2017-01-01T00:00:00Z as milliseonds
    .node(3);                   // node number

let generator = Generator::new(opts);

Also, time function is can be set. If you want to use plain seconds unit instead of millisedond, you can do by this:

use frostflake::{Generator, GeneratorOptions};
use std::time::{SystemTime, UNIX_EPOCH};

fn my_time() -> u64 {
    let t = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    t.as_secs()
}

// use smaller time bits (because this is not milliseconds)
// use larger sequence bits
let opts = GeneratorOptions::default()
    .base_ts(0) // need this for avoid exceeding time value on smaller bit size
    .bits(36, 10, 18)
    .base_ts(1483228800) // base time should be second too
    .time_fn(my_time); // set my time function

let generator = Generator::new(opts);

Default configurations

Generator

Options Default value
bits 42=timestamp, 10=node, 12=sequence
base_ts 1483228800000 (2017-01-01T00:00:00Z as milliseonds)
node 0
time_fn return current milliseonds

GeneratorPool

Almost same as Generator, but GeneratorPool uses pool_id bit for distinguish each pools.

So default bit widths is:

Options Default value
bits 42=timestamp, 4=pool_id, 6=node, 12=sequence

All other options are same with Generator.

TODO

  • Support redis based automatic node_id generation like katsubushi
  • Support other async runtimes?

Patches or pull-requests are always welcome.

Dependencies

~0–0.8MB
~12K SLoC