continue writing the post

This commit is contained in:
JasterV 2025-06-02 21:00:22 +02:00
parent 56db98f23e
commit 8e8a89f279
2 changed files with 78 additions and 5 deletions

View file

@ -2,10 +2,10 @@
title: "Decoupling Elixir GenServers with Phoenix PubSub"
description: "A way to make our Genservers more easy to test and maintain by using PubSub"
pubDate: 2025-06-02
image: "./assets/me.png"
image: "./assets/elixir.svg"
---
## TLDR
# TLDR
In this post I'd like to talk about a way to decouple a GenServer in your Elixir application in a way that makes it very easy to test and decouples it completely from the rest of the system.
@ -17,12 +17,31 @@ Then I want to walk you through the process I went to solve these problems and w
## Automating a door
So the project we will look at is very simple.
It consists of an IoT application that controls a door and waits for messages from a server to lock or unlock the door.
### Architecture
- Websocket client
- Door GenServer
The application consists of:
The Door GenServer can receive a lock or unlock messages, and it will call the websocket client back to emit a "locked" or "unlocked" events when done.
- A Websocket client that listens for `lock`/`unlock` messages from a server and sends back a `locked` or `unlocked` message after the operations have succeeded.
In case of an error it will send an error message so the caller knows something is wrong.
We will not consider timeouts in here, just to make it as simple as possible.
- A GenServer that manages the state of the Door and is responsible for locking or unlocking it.
It is important to note that we are implementing a Websocket client, not server.
In this case we imagine there is a central server that is responsible for keeping track of the state of multiple doors in the house, and that there are users that can tell the server "lock door A".
We skip all of that for the sake of making this very simple, but I think having more context is important.
Let's look at a simple diagram.
Let's look at some code:
## Let's get into code
### Websocket client

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2122 2122" style="enable-background:new 0 0 2122 2122;" xml:space="preserve">
<g>
<path style="fill:#D1E1EB;" d="M1276.382,844.885V584.528h25.309c43.313,0,78.75-35.438,78.75-78.751
c0-43.313-35.437-78.751-78.75-78.751H819.63c-43.313,0-78.751,35.438-78.751,78.751c0,43.313,35.439,78.751,78.751,78.751h25.309
v260.357c-224.536,86.624-383.844,304.465-383.844,559.545c0,331.13,268.434,599.564,599.564,599.564
s599.564-268.434,599.564-599.564C1660.224,1149.35,1500.917,931.509,1276.382,844.885z"/>
<path style="fill:#9ECDE6;" d="M971.72,521.138h-25.311c-43.313,0-78.75-35.438-78.75-78.751c0-5.255,0.542-10.387,1.537-15.361
H819.63c-43.313,0-78.751,35.438-78.751,78.751c0,43.313,35.439,78.751,78.751,78.751h25.309v260.357
c-224.536,86.624-383.844,304.465-383.844,559.545c0,331.13,268.434,599.564,599.564,599.564
c63.676,0,125.017-9.962,182.593-28.352c-32.428,3.225-64.961,5.283-97.547,5.865c-86.115,1.539-173.238-7.17-255.647-33.108
c-81.667-25.705-157.182-68.89-218.663-128.716c-70.345-68.449-119.891-154.769-146.345-249.128
c-47.507-169.461-7.832-363.453,93.331-505.861c0,0,110.151-162.614,351.532-183.751c0.3-0.026,2.935-253.568,2.935-253.568
l161.067-42.847h142.466h25.309c38.058,0,70.015-27.367,77.213-63.39H971.72z"/>
<path style="fill:#FFFFFF;" d="M1319.442,485.334h-257.555c-9.684,0-17.608-7.924-17.608-17.608l0,0
c0-9.685,7.924-17.608,17.608-17.608h257.555c9.684,0,17.608,7.924,17.608,17.608l0,0
C1337.05,477.411,1329.126,485.334,1319.442,485.334z"/>
<path style="fill:#A75A97;" d="M1550.618,1278.821c-10.375,30.318-226.09,54.53-490.727,54.53
c-258.464,0-470.295-23.094-489.703-52.417c-9.925,39.532-15.256,80.886-15.256,123.495c0,279.306,226.423,505.728,505.728,505.728
c279.305,0,505.729-226.422,505.729-505.728C1566.389,1361.063,1560.885,1318.989,1550.618,1278.821z"/>
<path style="fill:#65488F;" d="M1062.017,1786.685c-15.778-25.921-31.536-51.848-47.568-77.609
c-13.992-22.482-27.311-46.133-34.015-71.944c-6.415-24.704-5.727-51.056,3.993-74.834c7.885-19.29,17.571-37.801,28.077-55.782
c24.306-41.601,52.85-80.709,82.751-118.432c14.948-18.858,30.363-37.36,46.173-55.515c-26.522,0.513-53.754,0.783-81.536,0.783
c-258.464,0-470.295-23.094-489.703-52.417c-9.925,39.532-15.256,80.886-15.256,123.495c0,279.306,226.423,505.728,505.728,505.728
c24.893,0,49.354-1.831,73.285-5.305C1109.969,1865.463,1085.993,1826.074,1062.017,1786.685z"/>
<path style="fill:#CC7AA8;" d="M1059.892,1333.351c264.637,0,480.351-24.212,490.727-54.53c0.258-0.758,0.429-1.52,0.429-2.286
c0-31.378-219.898-56.816-491.155-56.816c-271.258,0-491.155,25.438-491.155,56.816c0,1.48,0.492,2.947,1.452,4.398
C589.596,1310.257,801.428,1333.351,1059.892,1333.351z"/>
<ellipse transform="matrix(0.5 -0.866 0.866 0.5 -274.6768 1609.1263)" style="fill:#FFFFFF;" cx="1256.206" cy="1042.44" rx="105.729" ry="210.461"/>
<path style="fill:#FFFFFF;" d="M1526.553,1228.9c-13.704,15.096-41.065,12.58-61.112-5.619
c-20.047-18.199-25.188-45.19-11.484-60.286c13.705-15.096,41.066-12.58,61.112,5.619
C1535.116,1186.813,1540.258,1213.804,1526.553,1228.9z"/>
<path style="fill:#F39452;" d="M1065.225,174.248c-111.51,13.509-203.883,15.245-212.964,4.374l10.552,248.403h390.743
l19.214-298.554l-0.184,0.021C1262.894,141.262,1174.265,161.038,1065.225,174.248z"/>
<path style="fill:#EF7747;" d="M1164.241,384.442c-32.827-4.501-67.072-11.337-96.265-27.733
c-11.758-6.602-22.574-15.075-30.575-26.016c-10.341-14.138-13.722-32.001-15.545-49.074c-3.667-34.332,0.149-68.572,2.427-102.845
c-92.436,9.219-164.08,9.355-172.021-0.152l10.552,248.403h390.743l2.296-35.681
C1225.225,390.47,1194.604,388.605,1164.241,384.442z"/>
<path style="fill:#F8B88A;" d="M1065.225,174.248c109.04-13.21,197.668-32.986,207.362-45.755c0.665-0.877,0.972-1.721,0.875-2.527
c-1.52-12.548-97.216-11.277-213.742,2.84c-116.526,14.117-209.756,35.733-208.236,48.282c0.066,0.54,0.368,1.045,0.777,1.535
C861.343,189.493,953.715,187.757,1065.225,174.248z"/>
<path style="fill:#FFFFFF;" d="M1213.605,343.089L1213.605,343.089c-15.049-1.088-26.472-14.291-25.384-29.341l7.406-102.438
c1.088-15.049,14.291-26.472,29.34-25.384l0,0c15.049,1.088,26.472,14.291,25.384,29.34l-7.406,102.438
C1241.857,332.754,1228.654,344.177,1213.605,343.089z"/>
<ellipse transform="matrix(0.3838 -0.9234 0.9234 0.3838 -503.6756 2242.0808)" style="fill:#CC6098;" cx="1428.062" cy="1498.424" rx="133.823" ry="74.835"/>
<path style="fill:#CC6098;" d="M1361.324,1698.587c-11.376,22.513-34.099,33.941-50.753,25.525
c-16.654-8.416-20.933-33.488-9.557-56.001c11.376-22.513,34.099-33.941,50.753-25.525
C1368.422,1651.001,1372.7,1676.074,1361.324,1698.587z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB