"Timebox" the lifespan of a Process + lookup by "name"

In a Phoenix application, I’m trying to create a system to make it easy for an Apple TV app to authenticate without having to enter a username/password with the TV remote.
The idea is that the TV app shows a unique code which you can then enter on an authenticated web page on your phone or browser.
This is similar to the “Easy Auth” series on NSScreencast.com and how you can login to the Youtube Apple TV app (https://youtube.com/activate).

An activation code should expire after a certain amount of time.

I was thinking that instead of storing the active codes in Redis or another db, an active activation code could be modeled as a Process (holding the activation code and some extra properties like the device id) that destroys itself after a certain timeout.

I’m really new to the platform so I’m wondering if this is the right approach, and what the best way to implement this would be.

I’ve toyed around with GenServer and Agent, but I’m struggling to get anything working.
Some things I ran into:

  • What version of start_link to use, and which arguments to give it
  • How to “find” a process based on the activation_code
  • How to avoid using atoms as Process names to avoid running into the atom limit

Any feedback would be greatly appreciated!

–Tim

1 Like

It’s very common for newcomers to Erlang/Elixir to see processes and all of their neat properties and potential, and want to use that to model everything they can. It takes time to learn when that instinct is on the right track.

https://www.theerlangelist.com/article/spawn_or_not

Your specific example use-case could be really straightforward to model with database rows and an expired_at or expires_at column, which would allow any running copy of your software to service the requests rather than potentially requiring “sticky sessions” or similar technique that connect specific users to specific backend instances. It wouldn’t require you to possibly explore the worlds of distributed state or distributed supervision trees, either. You’d just want to clean up that table every so often, if your business domain allows for it.

If you’d like to continue strictly as a learning exercise, here are a few pointers:

  • You can register processes for later lookup, without using an unbounded number of atoms, using either the Registry module from the stdlib or another module you write using a via-tuple.
  • Locating such processes for things like GenServer.call then use a via-tuple in place of the atom or pid that you’re maybe more familiar with.
  • You can set up timers for your long-lived processes with :timer.send_interval or Process.send_after, which might be a useful way to trigger a delayed clean-up step
  • The gen_statem behavior from Erlang allows timing out from specific states of the state-machine after no events have been received for a while, which could have similar applications as the above without being a simple no-nonsense expiration timer - for example, if a user interacts with the state machine, it can “refresh” the timeout, which is something you’d have to DIY in a GenServer, although it’s very doable.
  • Some of the available caching libraries like Cachex and con_cache support TTLs/expiration without requiring an external-to-BEAM infrastructure component
3 Likes