Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequence generation is not correct: it should reset when the timestamp increases #5

Closed
Qqwy opened this issue Feb 19, 2024 · 2 comments · Fixed by #6
Closed

Sequence generation is not correct: it should reset when the timestamp increases #5

Qqwy opened this issue Feb 19, 2024 · 2 comments · Fixed by #6

Comments

@Qqwy
Copy link
Contributor

Qqwy commented Feb 19, 2024

Hi there! First of all, thank you for this great crate! The Snowflake trait is a great way to make snowflakes customizable, and it seems like a much better approach than the other crates out there.

However, I think I've found a small bug in the way sequence generation is done.
Or, to be precise, snowflaked does it differently from the way Twitter does it (which I think is how most other snowflake generation libraries also do it).

Specifically, I believe that the sequence number should be reset whenever now > components.timestamp(), rather than only rolling over when 4095 is hit.

Not doing so gives rise to the following race condition (which I experienced in my test suite):

CommonSnowflake { timestamp: 1708353054919, instance: 42, sequence: 4093 }
CommonSnowflake { timestamp: 1708353054919, instance: 42, sequence: 4094 }
CommonSnowflake { timestamp: 1708353054920, instance: 42, sequence: 4095 }
CommonSnowflake { timestamp: 1708353054920, instance: 42, sequence: 0 }
CommonSnowflake { timestamp: 1708353054920, instance: 42, sequence: 1 }

There are other ways to fix this race condition, but following the original snowflake spec is probably the best way to do so.

@Qqwy
Copy link
Contributor Author

Qqwy commented Feb 19, 2024

As a minimal test, consider:

let generator = Generator::new(42);
let ids: Vec<u64> = (1..=10_000).map(|_| generator.generate()).collect();
for (id, next_id) in ids.iter().zip(ids[1..].iter()) {
    assert!(id < next_id, "Expected ids to be sorted and duplicate-free, but element {:?} is not < than {:?}", (id.timestamp(), id.instance(), id.sequence()), (next_id.timestamp(), next_id.instance(), next_id.sequence()));
}

@MrGunflame
Copy link
Owner

Hey, thanks for reporting this. You are correct, the timestamp should reset when now > timestamp. I am open to accepting a patch if you're willing to fix this, otherwise I'll get this fixed later this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants