hubertlepicki

hubertlepicki

So I kind of knew of this behavior and I stumbled upon it before but actually I am not sure what is the best way to solve / debug the issue.

So on production I am observing on occasion requests that are being sent to our system, and I can see the initial Logger line for the request as being handled by the app:

12:59:19.614 request_id=Fnc9RXabbAmFCZ0AAAdG [info] GET / 

but for these requests I am missing the log entry that a response was sent, i.e. no line like:

12:59:19.624 request_id=Fnc9RXabbAmFCZ0AAAdG  Sent 200 in 10ms

As far as I understand, this means the Cowboy handler process exitted before it’s registered “before_send” callback is executed, which is being installed here by Plug.Logger:

https://github.com/elixir-plug/plug/blob/v1.11.1/lib/plug/logger.ex#L35

So, I have stumbled upon the situation that my requests fail, process exits, and I have no entry in logs, nor in AppSignal (we use Appsignal.Plug) as it’s just handling throws and exceptions, but not exits.

Since Cowboy is built not on OTP primitives, we don’t see the usual crash reports for these processes either. They seem to silently fail.

Now, I need to debug and fix the issue but also monitor for this not happening in the future. So I have several questions:

  1. Am I missing something that on Cowboy / Plug / Phoenix level would detect, log and report these mysterious exits? I think the answer is “no” and that situation is simply not handled by the above.

  2. The implementation should be as per this blog post (of mine) from 2 years ago, i.e. start a monitoring process for each request handler in a plug and log / report exits or is there some ready to use piece of infrastructure / library I should be using instead? When web requests fail in Elixir and Phoenix | AmberBit Sp. z o. o.

Showing Posts 1 to 10

al2o3cr

al2o3cr

What’s the log level set to in production? IIRC the “unexpected exit” reports are written at info.

axelson

axelson

Scenic Core Team

Hmm, seems like a potentially similar issue to this recent (unresolved) post: Phoenix didn't handle some http requests

josevalim

josevalim

Creator of Elixir

Most likely the request process crashed due to a link. Cowboy should report those, unless the exit reason is shutdown, which doesn’t log anything throughout OTP.

Given you know the request path, see if that path is starting or communicating with any process that might exit.

hubertlepicki

hubertlepicki OP

So what is happening is when a linked process crashes (as in throws an exception) I am getting crash reports properly:

  def index(conn, _params) do                                                                                                                                            
    Agent.start_link fn ->                                                                                                                                               
      raise "wat"                                                                                                                                                        
    end                                                                                                                                                                  
                                                                                                                                                                         
    render(conn, "index.html")                                                                                                                                           
  end 
09:31:10.288 [error] CRASH REPORT Process <0.1088.0> with 1 neighbours crashed with reason: #{'__exception__' => true,'__struct__' => 'Elixir.RuntimeError',message => <<"wat">>} in 'Elixir.UI.DashboardController':'-index/2-fun-0-'/0 line 8
09:31:10.289 [error] Cowboy stream 8 with ranch listener 'Elixir.UI.Endpoint.HTTP' and connection process <0.995.0> had its request process exit with reason: #{'__exception__' => true,'__struct__' => 'Elixir.RuntimeError',message => <<"wat">>} in 'Elixir.UI.DashboardController':'-index/2-fun-0-'/0 line 8

When a linked process exits, however, like this:

  def index(conn, _params) do                                                                                                                                            
    Agent.start_link fn ->                                                                                                                                               
      Process.exit(self(), :kill)                                                                                                                                        
    end                                                                                                                                                                  
                                                                                                                                                                         
    render(conn, "index.html")                                                                                                                                           
  end   

I only get the initla Plug.Logger line and then nothing, and the browser keeps spinning and loads this error:

Note: the exit reason can be anything, not just :normal, and Cowboy won’t report anything for me.

Similarly to zhangzhen 's problem, this is happening on prod when I handle webhooks (although from different system) and we did have issues that for example the JSON they were sending us didn’t comply with standard. I suspect there’s a similar issue here, that the machine-generated payload somehow is messed up and some linked process (or the process of handler) performs exit() ? rather than a crash.

My plan is, as I know the path that this is happening on, is to install a monitor from within a custom plug, and collect the exit reasons from requests on that path and maybe this will give me some idea what’s going on behind the scenes.

It’s a separate question if Cowboy / Plug / Phoenix should handle the situation more gracefully. In Cowboy’s documentation there are some hints that you want to monitor handler processes, like this one from here https://ninenines.eu/docs/en/cowboy/2.6/guide/handlers/:

This callback is optional because it is rarely necessary. Cleanup should be done in separate processes directly (by monitoring the handler process to detect when it exits).

but I understand that monitoring all handlers would have some performance punishment.

josevalim

josevalim

Creator of Elixir

Can you try with something other than kill? That’s the “strongest” exit signal someone can submit and therefore we can’t generalize it.

Note this is not related to handlers though. Who is reporting this from Cowboy’s side is the connection, not the handler. And given Cowboy is already monitoring the handler process, I don’t see why it wouldn’t report other reasons too.

josevalim

josevalim

Creator of Elixir

I have investigated this a bit, the issue is here:

https://github.com/ninenines/cowboy/blob/master/src/cowboy_stream_h.erl#L127-L141

Cowboy is not handling a {'EXIT', Pid, Whatever}, which is the format of exit reasons from linked processes. I would open up an issue on Cowboy and ask if they would consider adding a catch clause.

hubertlepicki

hubertlepicki OP

Oh, I did assume they don’t intend to handle it but looking at the code it is more likely an unintended bug. I will report to them.

hubertlepicki

hubertlepicki OP

Actually I looked at the code more in details in Cowboy and it looks like they have the try/catch clause and this is the only way they are catching these exits.

So I think it is meant to catch exits coming from the process itself (i.,e. using exit("SOMETHING") in Elixir), but if some other process sends it an exit signal (i.e. if using Process.exit(pid, "SOMETHING") thisi s not being caught unless process is trapping exits, but even then the :kill wouldn’t be captured I believe.

So it’s not as simple as adding clause here as it won’t be caught by try/catch clause. The only way to detect this situation I think is to monitor the process that is being sent an exit signal.

I will open an issue on Cowboy but I doubt this is something they want to handle. We’ll see.

josevalim

josevalim

Creator of Elixir

This is not correct. cowboy_http is handling exits and the code I linked above is the result of receiving a {'EXIT', PID, Reason):

https://github.com/ninenines/cowboy/blob/master/src/cowboy_http.erl#L258-L260

hubertlepicki

hubertlepicki OP

Yes, verified that, you are correct. It only won’t catch :kill I think.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews