<div dir="ltr"><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Feb 23, 2020 at 1:37 AM by <<a href="mailto:by@meetlost.com">by@meetlost.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div>Although there are some other problems (on my running system, the established WebSocket connection (process) been killed after the upgrade), the whole thing works fine.</div><div><br></div><div>I will investigate more about why the running process been killed after the upgrade, I think the link below might be helpful:</div><div><a href="https://github.com/lrascao/rebar3_appup_plugin/blob/develop/doc/UPGRADE_DOWNGRADE.md#soft-vs-brutal-purge" target="_blank">https://github.com/lrascao/rebar3_appup_plugin/blob/develop/doc/UPGRADE_DOWNGRADE.md#soft-vs-brutal-purge</a></div><div><br></div></div></blockquote><div><br></div><div>Yeah it's likely the soft vs. brutal purge thing will be significant. On a long-lived process that may be hanging and doing nothing (just waiting for a message), more than one upgrade can take place before the next message is handled, which will cause a failure when the process is killed for holding on to an old version. Either all these processes need to be sent a message to force them to load a local module reference (fully-qualified call), or drop old ones (i.e. local funs like <span style="font-family:monospace">fun f/2</span> or closures like <span style="font-family:monospace">fun(X) -> X + 1 end</span>) which are technically references to the module version whence they were declared.</div><div><br></div><div>Another common pattern is going to see some servers die when their acceptor pool crashes for the same reasons -- the acceptors maintain a reference to an older module, and following a couple of reloads, they get killed all at once in a kind of storm. Ranch, which underpins cowboy, is the most frequently seen one doing this as its acceptor pool isn't safe (<a href="https://github.com/ninenines/ranch/blob/ae84436f7ceed06a09e3fe1afb30e675579b7621/src/ranch_acceptor.erl#L35">all accept calls wait for infinity</a>, which as far as I can tell is a performance-based decision); a workaround for this is to shrink your acceptor pool to be small enough that you can reasonably expect all acceptors to be used between two upgrades.</div><div><br></div><div> A server that would otherwise be safe for reloads in that case could be Elli, which has<a href="https://github.com/elli-lib/elli/blob/c16ac7dca11947cbb1ded6f72764943193e6fdcf/src/elli_http.erl#L48-L54"> a timeout-then-reload pattern</a> that specifically guards for upgrades (as long as they happen less frequently than the accept timeout duration), or YAWS, <a href="https://github.com/klacke/yaws/blob/365d4f83d5f29907945b6efa8575749150af022d/src/yaws_server.erl#L1133-L1146">which will start a new acceptor process on a timeout</a> for a similar result.</div><div><br></div><div>Do note that this latter point on acceptor pools is only tangentially related to websockets, since having the server handle its acceptor pool timing out (and allowing upgrades) will not prevent websocket connections from dying during upgrades; they're just another thing to test and worry about.<br></div></div></div>