Dans mon application, tous les utilisateurs connectés sont représentés par un GenServer, j'appelle un UserAgent, qui garde en mémoire l'état de chaque utilisateur. Tous ces processus sont enregistrés dans le cluster dans un registre distribué basé sur Horde avec un identifiant unique. Chaque fois que l'utilisateur effectue une action, l'application cliente envoie l'action à effectuer avec le user_id. Côté serveur, le contrôleur vérifie les paramètres (obligatoires, facultatifs, syntaxe, etc.) et appelle éventuellement UserAgent.the_action(user_id, other_params). La fonction the_action(...) envoie simplement un message au serveur avec l'action à effectuer : GenServer.call(via_tuple(id), {:the_action, params}).

Dans certains cas, le UserAgent référencé par user_id n'existe plus, par exemple parce que l'utilisateur était inactif depuis un certain temps et que le processus avait été nettoyé (la session avait expiré) ou parce que des parties du cluster ne sont pas accessibles à ce moment (cas d'utilisation imaginaire pour le moment). Dans ces situations, l'appel GenServer.call(via_tuple(id), {:the_action, params}) entraîne l'erreur ci-dessous qui bloque également le processus de point de terminaison HTTP (#PID<0.1359.0> ci-dessous) qui à son tour entraîne une erreur HTTP 500 (le dump api call, eh bien, vide l'état d'un processus à des fins de débogage):

[error] #PID<0.1359.0> running AppWeb.Endpoint (connection #PID<0.1358.0>, stream id 1) terminated
Server: localhost:4001 (http)
Request: GET /api/v1/dump/5f534b99d6ca3fe1ff6d2f78
** (exit) exited in: GenServer.call({:via, Horde.Registry, {App.DReg, "5f534b99d6ca3fe1ff6d2f78"}}, :dump, 5000)
    ** (EXIT) no process: the process is not alive or there's no process currently associated \
        with the given name, possibly because its application isn't started

Je n'arrive pas à comprendre comment intercepter cette erreur. J'ai fini par appeler Horde.Registry.lookup(App.UserAgent.via_tuple(user_id)) dans la partie client du UserAgent, puis appeler GenServer.call() with the returned pid` ou renvoyer une erreur au contrôleur si le processus n'a pas été trouvé.

Je me demandais s'il y avait une meilleure façon.

1
mszmurlo 6 sept. 2020 à 09:24

1 réponse

Meilleure réponse

Voici comment GenServer.call/3 gère ​​les erreurs dans . Il appelle néanmoins whereis/1, vous pouvez donc soit appeler whereis/1 vous-même, soit répliquer la logique du code que j'ai lié ou utiliser Kernel.SpecialForms.try/1 à catch l'exception.

2
Aleksei Matiushkin 6 sept. 2020 à 06:40