How to create a short code id?

i’ve been working on an idea and a need a simple short code id, i didnt want to pull in a library just for that, i thought sqids would be an overkill for my usage.
so i looked some uuidv4 generation code and worked on something like the following(that would be just the first part of the uuidv4):

lists:flatten(io_lib:format("~8.16.0b", [crypto:rand_uniform(1, round(math:pow(2, 32))) - 1])).

but I feel i’m doing something wrong/shitty, any suggestion on a proper solution for that?

To avoid clashes you may want to look at erlang:unique_integer/1.

1 Like

thanks. i’ve ended with something like:

id() ->
    P1 = erlang:unique_integer([positive]),
    P2 = erlang:unique_integer([positive]),
    Str = io_lib:format("~4.16.0b~3.32.0b", [P1, P2]),
    binary:list_to_bin(Str).

In a distributed environment, that is, between multiple Erlang nodes, erlang:unique_integer/1 does not guarantee global uniqueness. Each node maintains its own counter, and conflicts can occur if multiple nodes generate unique integers at the same time.

I use GitHub - fogfish/uid: erlang fault tolerant service to generate unique identities

-spec uid() -> binary().
uid() ->
    uid("").

-spec uid(integer() | list() | binary()) -> binary().
uid(Prefix) ->
    U1 = uid:encode64(uid:g()),
    iolist_to_binary([ec_cnv:to_binary(Prefix), U1]).
(imboy@127.0.0.1)42> imboy_func:uid("p").
<<"p.5jeiF5.Kr57hw.A">>
(imboy@127.0.0.1)43> imboy_func:uid("p").
<<"p.5jeiF5.Kr5BTF.B">>
(imboy@127.0.0.1)44> imboy_func:uid("p").
<<"p.5jeiF5.Kr5DVk.C">>

(imboy@127.0.0.1)32> uid:encode64(uid:g()).
<<".5jehk5.Kr6SPZ.0">>
(imboy@127.0.0.1)33> uid:encode64(uid:g()).
<<".5jehk5.Kr6TMg.1">>
(imboy@127.0.0.1)34> uid:encode64(uid:g()).
<<".5jehk5.Kr6ULg.2">>
(imboy@127.0.0.1)35> uid:encode64(uid:g())。
* 1:22: illegal character
(imboy@127.0.0.1)35> uid:encode64(uid:g()). 
<<".5jeiF5.Kr3QLZ.3">>

for my use case it’s not relevant, those ids just need to avoid conflict in a local context. the sloppy solution with the unique_integer is more than enough for me.

but thanks for the suggestion, i gonna check the library.

Also note that unique_integers are unique only for the lifetime of a node. That is, if you restart a node, there may be (or rather, there are likely to be) clashes with unique integers produced by previous runs of the same node. That is to say, if your supposedly-unique identifiers are in some way relevant outside of a running node, unique_integer is not a safe bet.

2 Likes

We’ve been using identifiers based on {erlang:system_time(millisecond), erlang:unique_integer([positive])} which for us was light enough and safe enough.

4 Likes