Skip to content

feat(workflow_engine): Action Filter cache invalidation#111060

Merged
saponifi3d merged 11 commits intomasterfrom
jcallender/aci/invalidate-action-filter-cache
Mar 23, 2026
Merged

feat(workflow_engine): Action Filter cache invalidation#111060
saponifi3d merged 11 commits intomasterfrom
jcallender/aci/invalidate-action-filter-cache

Conversation

@saponifi3d
Copy link
Copy Markdown
Contributor

Description

Signal handlers for cache invalidation. There's not a rollout flag included here yet, because any exceptions or failures are limited to the scope of these invalidation methods and it keeps that a little simpler.

When we invalidate the Action Filters / Data conditions:

Model Signal Reason
WorkflowDataConditionGroup post_save When an action filter is created on a workflow
WorkflowDataConditionGroup pre_delete When an action filter is removed from the workflow
DataConditionGroup post_save When an update to the logic type in the condition
DataCondition post_save When a condition on a filter is created or changed
DataCondition pre_delete When a condition on the filter being removed

Remaining Work

  • Update the evaluate_workflows_action_filters method to read from the cache with a rollout flag.

@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 19, 2026
@saponifi3d saponifi3d marked this pull request as ready for review March 19, 2026 22:56
@saponifi3d saponifi3d requested a review from a team as a code owner March 19, 2026 22:56
@saponifi3d saponifi3d requested review from ceorourke and kcons March 20, 2026 16:52
Comment on lines +34 to +35
# TODO -- see if we can determine if the DataCondition is
# an ActionFilter, to skip querying for the workflow.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is unfortunately - since I was recently doing the workflow -> rule serializer I checked how it's handled there (link) and it's just based off of whether the workflow has a when condition group

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my thought was the handler of each data condition has a group, which is what we use to send them to different sections in the UI. I think if we can get access to the handler, we could filter before hand. If it's an operator condition type, then yeah, we'd have to check the WorkflowDataConditionGroup table.

Comment on lines +217 to +227
workflow = self.create_workflow()
action_filters = self.create_action_filters_for_workflow(
workflow=workflow,
num_conditions=1,
)
workflow_two = self.create_workflow()
action_filters_two = self.create_action_filters_for_workflow(
workflow=workflow_two,
num_filters=2,
num_conditions=1,
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a huge deal but any way to reduce the duplication of these across tests?

# Warm the cache
cache_data: ActionFiltersByWorkflow = {workflow.id: condition_groups}
cache_keys = self.populate_action_filter_cache(cache_data)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be like the previous test which has an assertion that there is data in the cache in the "warming" step just to show there is something to invalidate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could, but i tend to like to have test cases isolated when the logic is differing. that way if 1 unit of logic fails, 1 test should fail (🤞). It's a bit more DB overhead to do that, but I've found it really useful when refactoring in the future.

Copy link
Copy Markdown
Member

@kcons kcons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable to me; I think the main risk here is likely cache inconsistency due to some overlooked nuance or a behavior tweak a few months from now.
But, we have low enough write rate and short enough TTL and some tolerance for slightly stale data, so small problems range from theoretically observable to unreproducible, so maybe it's not worth investing much though in.
I gues we could follow up with a low-probability cache check thing that pretends there was a cache it, compares, and spawns a task if there is a difference to check again shortly (and maybe again) to check how eventual our consistency is. Not hard to do, but probably not worth the complexity until we have reason to believe something might be fishy.

@saponifi3d saponifi3d merged commit e9fdb52 into master Mar 23, 2026
70 checks passed
@saponifi3d saponifi3d deleted the jcallender/aci/invalidate-action-filter-cache branch March 23, 2026 16:51
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants