dashbitco / broadway

Concurrent and multi-stage data ingestion and data processing with Elixir

Home Page:https://elixir-broadway.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dialyzer error on ack_immediately/1

mortont opened this issue · comments

When using Broadway.Message.ack_immediately/1 on a single message and running mix dialyzer on the code, dialyzer returns the following error:

lib/test/test_broadway.ex:38:callback_arg_type_mismatch
The inferred type for the 2nd argument is not a
supertype of the expected type for the handle_message/3 callback
in the Broadway behaviour.

Success type:
[
  %Broadway.Message{
    :acknowledger => {atom(), _, _},
    :batch_key => _,
    :batch_mode => :bulk | :flush,
    :batcher => atom(),
    :data => _,
    :metadata => %{atom() => _},
    :status =>
      :ok
      | {:failed, binary()}
      | {:error, _, [any()]}
      | {:exit, _, [any()]}
      | {:throw, _, [any()]}
  },
  ...
]

Behaviour callback type:
%Broadway.Message{
  :acknowledger => {atom(), _, _},
  :batch_key => _,
  :batch_mode => :bulk | :flush,
  :batcher => atom(),
  :data => _,
  :metadata => %{atom() => _},
  :status =>
    :ok
    | {:failed, binary()}
    | {:error, _,
       [
         {(... -> any), [any()] | non_neg_integer(), Keyword.t()}
         | {atom(), atom(), [any()] | non_neg_integer(), Keyword.t()}
       ]}
    | {:exit, _,
       [
         {(... -> any), [any()] | non_neg_integer(), Keyword.t()}
         | {atom(), atom(), [any()] | non_neg_integer(), Keyword.t()}
       ]}
    | {:throw, _,
       [
         {(... -> any), [any()] | non_neg_integer(), Keyword.t()}
         | {atom(), atom(), [any()] | non_neg_integer(), Keyword.t()}
       ]}
}

Looking around it seems like others have run into this issue as well here. Of note, dialyzer is happy with passing a list of messages to ack_immediately/1. Also, the code functions as expected, so I think this is a spec or dialyzer error. Relevant code to reproduce:

  @impl true
  def handle_message(_, message, _) do
    message |> Message.ack_immediately
  end

A PR is welcome!

Looking at this more, I found the fix but I don't understand why it's the fix. In lib/broadway/message.ex if you change

  def ack_immediately(%Message{} = message) do
    [message] = ack_immediately([message])
    message
  end

to

  def ack_immediately(%Message{} = message) do
    ack_immediately([message]) |> List.first
  end

dialyzer is happy. Based on my understanding, they should be equivalent so I'm not sure why one generates a dialyzer error while the other doesn't. Something seems fishy with dialyzer here... I don't think this is worth a PR since everything works as expected, but let me know if you think otherwise.

Yes, if that's the fix, then I agree with you. I will close but I will be glad if someone finds another fix and wants to submit a PR :) Thanks for the follow up!