Conditionally send subscription events

Hi @benwilson512

I’m trying to find a way to conditionally send a subscription event. For example, if a subscription operation is sent from the same session as the mutation operation that triggered it, I want to avoid sending an event to the client, because they will have already received the mutation payload.

I found that if I return {:ok, :any_atom} from a subscription field resolver, no event is sent. If I send {:ok, nil}, an event is sent with nil as the payload.

The former is what I want and seems to work, but I’m not sure why it works. Could you shed some light on the Absinthe mechanics here? And if there’s a better way to handle this, I’d love to know.

That does seem weird, are you sure it isn’t just causing a crash and then that’s why it isn’t publishing?

As far as your goal goes, how are you determining that it is the same session? What is your plan if the same user has multiple browser tabs open? I’m not entirely sure this is a desirable optimization.

I don’t disagree that it’s a bit weird, but it’s a product request so, you know.

The session id is generated client-side on a per-window/tab basis. It gets attached to the Graphql context, and also to mutation payloads. The subscription resolver compares the id on the context and the mutation payload.

I was hoping I could return an {:ok, :ignore} tuple and intercept that result somewhere at the phoenix channel level, swallowing the message there. Any thoughts on how I might be able to plug into Absinthe’s channel layer?

@benwilson512 This is what I came up with. Do you have any suggestions about other ways I might be able to handle this?

      resolve(fn %{metadata: metadata} = entity, _args, %{context: context} ->
        ignore = context[:session_id] && context[:session_id] == metadata[:session_id]

        if ignore do
          {:ok, nil}
          {:ok, entity}

      middleware(fn resolution, _ ->
        if resolution.value == nil do
          # This results in no event being sent. It's not clear to me if this is causing a crash or not.
          Map.put(resolution, :state, :unresolved)
1 Like

@benwilson512 It doesn’t seem to be crashing. If I raise in the subscription resolver, my test process doesn’t crash. I confirmed that they’re the same process.

The middleware approach does raise though with: [error] no function clause matching in Absinthe.Middleware.Telemetry.on_complete/2.

It seems like Absinthe is rescuing exceptions at a high level and not crashing; does that sound right to you?