SnowflakeId (snowflake_id v0.1.1)
Generates SnowflakeId's. This struct implements the Enumerable
protocol,
so you can use this with all the functions from Enum
and Stream
modules.
This implementation is functional and does not use any GenServer to store the state.
# override the time function for the test
iex> get_time = fn -> 1630163558780 end
iex> generator = SnowflakeId.new(1, 1, get_time: get_time)
iex> Enum.at(generator, 0)
6837401535245324288
iex> generator |> Enum.at(0) |> Integer.to_string(2)
"101111011100011010101000111100001011111000000100001000000000000"
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^xxxxxyyyyyzzzzzzzzzzzz
#^: timestamp
#x: machine_id
#y: node_id
#z: index
More realistic example:
iex> my_data =
...> SnowflakeId.new(1, 1)
...> |> Enum.take(10)
...> |> Enum.map(fn id ->
...> # insert your data in your database
...> %{id: id, name: "my_id_#{id}"}
...> end)
iex> length(my_data)
10
If you want to not use the Enumerable
protocol you can do it yourself by:
# override the time function for the test
iex> get_time = fn -> 1630163558780 end
iex> generator = SnowflakeId.new(1, 1, get_time: get_time)
iex> SnowflakeId.format_id(generator)
6837401535245324288
iex> generator = SnowflakeId.next(generator)
iex> SnowflakeId.format_id(generator)
6837401535245324289
Small warning, because the timestamp only uses 41 bits and the default timestamp starts from 1970. The maximum time that can be stored is:
iex> bits = 0b11111111111111111111111111111111111111111
iex> DateTime.from_unix(bits, :millisecond)
{:ok, ~U[2039-09-07 15:47:35.551Z]}
You can mitigate this by using your own timestamp function or use the helper function:
# from the start of 2000
iex> from = ~U[2000-01-01T00:00:00Z]
iex> get_time = SnowflakeId.timestamp_factory(from)
iex> with_own_get_time = SnowflakeId.new(1, 1, get_time: get_time)
iex> default_get_time = SnowflakeId.new(1, 1)
iex> Enum.at(with_own_get_time, 0) < Enum.at(default_get_time, 0)
true
we can now use this longer:
iex> bits = 0b11111111111111111111111111111111111111111
iex> ~U[2000-01-01T00:00:00Z] |> DateTime.add(bits, :millisecond) |> DateTime.truncate(:second)
~U[2069-09-06 15:47:35Z]
Link to this section Summary
Functions
Format the struct to return a id
Create a new SnowflakeId
struct
Update the struct to the next identifier
Default function to return the current timestamp in milliseconds
Helper function to generate a zero-arity function that returns the amount of milliseconds since epoch
Create a new SnowflakeId
struct but with some extra checks. For more info check new/3
Link to this section Types
opts()
Specs
Specs
Link to this section Functions
format_id(snowflake_id)
Specs
Format the struct to return a id
new(machine_id, node_id, opts \\ [])
Specs
Create a new SnowflakeId
struct
options:
:get_time : (-> integer) override the function to get the current timestamp, this function should return the time since an epoch in milliseconds. by defaut it uses
:os.system_time(:millisecond)
:bulk : boolean Don't check the time on every iteration, but only when the maximum amount of indexes is filled, which is
0..4095
This can be handy if you know you are going to generate a lot of indexes at once.
next(state)
Specs
Update the struct to the next identifier
os_system_time()
Specs
os_system_time() :: integer()
Default function to return the current timestamp in milliseconds
timestamp_factory(epoch)
Specs
timestamp_factory(DateTime.t()) :: (() -> integer())
Helper function to generate a zero-arity function that returns the amount of milliseconds since epoch
try_new(machine_id, node_id, opts \\ [])
Specs
Create a new SnowflakeId
struct but with some extra checks. For more info check new/3