AshWorkflow.Transformers.AddAttributes (AshWorkflow v0.7.0)

Copy Markdown View Source

Adds the state_entered_at attribute if not already defined on the resource.

This attribute tracks when the workflow entered its current state. It is used by timeout triggers to calculate whether a deadline has passed. The attribute is:

  • Type: :utc_datetime_usec
  • allow_nil?: false with a default of DateTime.utc_now/0
  • public?: true and writable?: false

writable?: false keeps the attribute out of every action's accept list and rejects it as an argument, so nothing outside AshWorkflow can move a record's anchor. AshWorkflow.Changes.RecordEvent writes it with Ash.Changeset.force_change_attribute/3, which bypasses writable?, and the atomic path writes it through the %{state_entered_at: expr(now())} map atomic/3 returns. Both are unaffected.

Every deadline on a step measures from this attribute, so a write from outside moves every one of them at once. A caller that genuinely needs to set it (backfilling imported records, say) can still reach it with force_change_attribute/3 or the data layer directly.

Does NOT add the :state attribute — that is handled by AshStateMachine's AddState transformer.

If the user has already defined a state_entered_at attribute, this transformer is a no-op.

every last-fired columns

Also adds one nilable :utc_datetime_usec attribute per every, named by AshWorkflow.Entities.Every.last_fired_field/2. AshWorkflow.Changes.RecordEvent writes it on that every's firing, and AshWorkflow.Transformers.AddScheduler measures the every's interval against it instead of state_entered_at. See AshWorkflow.Entities.Every for why firing no longer touches state_entered_at.

Nilable because an every that has not fired yet has no last-fired instant, which is also the case for an in-flight record written before the column existed. A nil column means the interval is measured from state_entered_at instead, so a record entering the step fires one whole interval later and needs no backfill.

Summary

Functions

after?(_)

Callback implementation for Spark.Dsl.Transformer.after?/1.

after_compile?()

Callback implementation for Spark.Dsl.Transformer.after_compile?/0.

before?(arg1)

Callback implementation for Spark.Dsl.Transformer.before?/1.

transform(dsl)

Callback implementation for Spark.Dsl.Transformer.transform/1.