ryanwinchester
`Workflow.add_cascade` dialyzer error when adding deps
When adding :deps to Workflow.add_cascade/4 I get a LSP/Dialyzer error
The function call will not succeed.
Oban.Pro.Workflow.add_cascade(
%Oban.Pro.Workflow{
:changesets => [
%Ecto.Changeset{
:action => atom(),
:changes => %{atom() => _},
:constraints => [
%{
:constraint =>
binary()
| %Regex{
:opts => binary() | [any()],
:re_pattern => _,
:re_version => _,
:source => binary()
},
:error_message => binary(),
:error_type => atom(),
:field => atom(),
:match => :exact | :prefix | :suffix,
:type => :check | :exclusion | :foreign_key | :unique
}
],
:data => %Oban.Job{
:__meta__ => _,
:args => map(),
:attempt => non_neg_integer(),
:attempted_at =>
nil
| %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:attempted_by => nil | [binary()],
:cancelled_at =>
nil
| %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:completed_at =>
nil
| %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:conf =>
nil
| %Oban.Config{
:dispatch_cooldown => pos_integer(),
:engine => atom(),
:get_dynamic_repo => nil | (-> atom() | pid()) | {atom(), atom(), [any()]},
:insert_trigger => boolean(),
:log =>
:alert
| :critical
| :debug
| :emergency
| :error
| false
| :info
| :notice
| :warn
| :warning,
:name => _,
:node => binary(),
:notifier => {atom(), Keyword.t()},
:peer => {atom(), Keyword.t()},
:plugins => [atom() | {atom() | Keyword.t()}],
:prefix => false | binary(),
:queues => Keyword.t(Keyword.t()),
:repo => atom(),
:shutdown_grace_period => non_neg_integer(),
:stage_interval => timeout(),
:testing => :disabled | :inline | :manual
},
:conflict? => boolean(),
:discarded_at =>
nil
| %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:errors => [
%{
:at => %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:attempt => pos_integer(),
:error => binary()
}
],
:id => pos_integer(),
:inserted_at => %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:max_attempts => pos_integer(),
:meta => map(),
:priority => 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9,
:queue => binary(),
:replace =>
nil
| [
[
:args
| :max_attempts
| :meta
| :priority
| :queue
| :scheduled_at
| :tags
| :worker
]
| {:available
| :cancelled
| :completed
| :discarded
| :executing
| :retryable
| :scheduled,
[
[
:args
| :max_attempts
| :meta
| :priority
| :queue
| :scheduled_at
| :tags
| :worker
]
]}
],
:scheduled_at => %DateTime{
:calendar => atom(),
:day => pos_integer(),
:hour => non_neg_integer(),
:microsecond => {non_neg_integer(), non_neg_integer()},
:minute => non_neg_integer(),
:month => pos_integer(),
:second => non_neg_integer(),
:std_offset => integer(),
:time_zone => binary(),
:utc_offset => integer(),
:year => integer(),
:zone_abbr => binary()
},
:state => binary(),
:tags => [binary()],
:unique =>
nil
| %{
:fields => [:args | :meta | :queue | :worker],
:keys => [atom()],
:period =>
:infinity
| pos_integer()
| {pos_integer(),
:day
| :days
| :hour
| :hours
| :minute
| :minutes
| :second
| :seconds
| :week
| :weeks},
:states => [
[
:available
| :cancelled
| :completed
| :discarded
| :executing
| :retryable
| :scheduled
]
],
:timestamp => :inserted_at | :scheduled_at
},
:unsaved_error =>
nil
| %{
:kind => :error | :exit | :throw | {:EXIT, pid()},
:reason => _,
:stacktrace => [
{(... -> any), [any()] | non_neg_integer(), Keyword.t()}
| {atom(), atom(), [any()] | non_neg_integer(), Keyword.t()}
]
},
:worker => binary()
},
:empty_values => _,
:errors => Keyword.t({binary(), Keyword.t()}),
:filters => %{atom() => _},
:params => nil | %{binary() => _},
:prepare => [
(%Ecto.Changeset{:action => atom(), :changes => map(), _ => _} ->
%Ecto.Changeset{:action => atom(), :changes => map(), _ => _})
],
:repo => atom(),
:repo_opts => Keyword.t(),
:required => [atom()],
:types => %{
atom() =>
atom()
| {:array | :assoc | :embed | :in | :map | :parameterized | :supertype | :try,
_}
},
:valid? => boolean(),
:validations => Keyword.t()
},
...
],
:check_deps => boolean(),
:grafts => _,
:id => binary(),
:names => %MapSet{:map => MapSet.internal(_) | :sets.set(_)},
:opts => map(),
:subs => map()
},
:orders,
(_ -> {[any()], [any()]}),
[{:deps, :init}]
)
breaks the contract
(t(), name(), cascade_capture(), add_cascade_opts()) :: t()
Marked As Solved
al2o3cr
I believe there’s a bug in the type for add_cascade_opts():
@type add_cascade_opts() :: [Oban.Job.option() | add_opts()]
@type add_opts() :: [
deps: name() | [name()],
ignore_cancelled: boolean(),
ignore_deleted: boolean(),
ignore_discarded: boolean()
]
The | operator normally expects options also separated with |, like Oban.Job.option():
@type option() ::
{:args, args()}
| {:max_attempts, pos_integer()}
| {:meta, map()}
| {:priority, 0..9}
| etc
As currently written, the type means “a list where elements are either tuples from Oban.Job.option() or a keyword list shaped like add_opts()”, so something like [[deps: :init]] would match the current spec. (but presumably fail catastrophically where options are parsed)
I don’t currently have access to Oban Pro, but updating the definition of add_cascade_opts would likely remove the error you’re seeing:
@type add_cascade_opts() :: [Oban.Job.option() | add_opt()]
@type add_opts() :: [add_opt()]
@type add_opt() ::
{:deps, name() | [name()]}
| {:ignore_cancelled, boolean()}
| {:ignore_deleted, boolean()}
| {:ignore_discarded, boolean()}
Beware that changes to files in deps/ won’t get picked up by Dialyzer until you nuke _build and any cached PLTs.
3
Also Liked
Popular in Questions
can someone please explain to me how Enum.reduce works with maps
New
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Hi,
is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Hi everyone,
I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
Other popular topics
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode.
The solution seems to be, in a hyphena...
New
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
Hello all!
I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
Hello, I have map which I want to convert it to string like this:
the map:
%{last_name: "tavakkoli", name: "shahryar"}
the string I ne...
New
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set?
Thanks.
New
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
I have VueJS GUIs with the project generated using Webpack.
I have Elixir modules that will need to be used by the VueJS GUIs.
I forese...
New
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!)
This post collects co...
New
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #javascript
- #code-sync
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









