Add a DagRun and TaskInstance event listener under the Kafka provider#68082
Conversation
|
I am confused by the use case here. Shouldn't this be an Asset Watcher? |
@vikramkoka No but it could be used together with an Asset Watcher. An Asset Watcher is essentially on the consumer side of events while this PR is on the producer side. The new listener produces a message to a Kafka topic for every event state change. We can consume the messages from the topic either using the existing consumer hook from the Kafka provider or using an Asset Watcher. For example, team A with Airflow installation A triggers dag1 and has enabled the listener which publishes events for every state change to a Kafka topic
Team B with Airflow installation B, is monitoring the same kafka topic and has a deferred task that waits to run after it consumes the message |
093a2ed to
a7e4f81
Compare
jason810496
left a comment
There was a problem hiding this comment.
Nice, LGTM overall.
this PR is on the producer side.
Yes. I think this is a valid feature for Kafka provider to support out of the box.
526b21c to
66cb2e7
Compare
|
Hey @jason810496, I've updated the PR. It took me more time than originally planned but I needed to try a few different approaches and test things thoroughly. I think that this last revision is better. I added two new options in the listener config
The producer, consumer and admin client hooks, all require an airflow connection to be initialized. The airflow connection carries an extra param JSON that holds all the necessary configuration. This configuration can also carry security info. Initially I tried to workaround it by defining Confluent kafka producer accepts the config as a dictionary. But the airflow connection json is a string, which has limitation like not being able to pass standard callables like I added an optional parameter to the base class, so that hook callers can pass the config dictionary directly to the hook without using a connection. The param is optional for back-compat reasons. Also, I added a new method that interprets the config callables whether they are part of the connection or the dictionary. It accepts dot-path strings pointing to locally installed packages. If a user has a connection but has also set a config key in the dict param, the dict value overrides the value from the connection. The changes are more extensive than originally planned but I think that they improve the way the hooks are configured greatly. Please take a look and let me know how it looks. I also updated all the tests. |
016c33a to
2a608c4
Compare
cb76100 to
c8b350e
Compare
d96ef22 to
c8b886d
Compare
jason810496
left a comment
There was a problem hiding this comment.
Nice, thanks. LGMT overall.
126a6b7 to
36a547d
Compare
|
The CI is green. It should be good to get merged. |
|
Thank you @shahar1 @jason810496 for the reviews and help! |
|
I went through the PR and here is what I think. This is not a replacement or alternative of asset watcher, they serve 2 different purposes:
The name listener is definitely confusing so we should change that. Here are some idea on how we could call it:
Not related but side comment on this one. If we know this is a business case needed by users we should make it a Airflow feature (with providers being able to hook their implementation such as Kafka) as opposed to a Kafka feature. |
|
@vincbeck Thank you for the comment! I've started working on renaming the listener to OpenLineage and Informatica also have a similar listener plugin Also see https://github.com/apache/airflow/blob/main/airflow-core/src/airflow/listeners/listener.py https://github.com/apache/airflow/blob/main/airflow-core/src/airflow/listeners/spec/dagrun.py |
|
Oh I see, interesting. It is kind of weird to me to expect deployment manager to have to install a plugin to set that up but that's another discussion we can leave for another time :) |
This PR is adding a listener under the Kafka provider which provides an implementation for the DagRun and TaskInstance state change event hooks.
The listener publishes a message to a pre-existing Kafka topic for every event. Each message has some extra metadata for the dag or task that the event belongs to.
DagRun events and TaskInstance events are separated and guarded behind different config flags. Both flags are disabled by default because each listener adds load to Airflow that users might not want.
The listener expects that the user has already created the topic and then defines it in the listener's config section. In case the topic doesn't exist, the listener doesn't fail. Instead it logs a warning and checks for the topic existence again after a configured interval.
Users can also filter events for dag runs based on dag_id and for tasks based on dag_id + task_id. For example, someone could choose to get only dag run state events for a particular dag and nothing else.
By adding a listener to the provider we can have dags consume from the Kafka topic and react to messages. When a particular message arrives, a deferred task could be triggered. This could also work for dags across multiple Airflow installations, all sharing the common topic. For that reason, I also added a
sourceconfig key, so that users can distinguish where the messages came from.The listener follows the same format as the openlineage one
https://github.com/apache/airflow/blob/main/providers/openlineage/src/airflow/providers/openlineage/plugins/listener.py
Testing
I've added unit tests and also a simple integration test that uses an actual broker. I've also tested the changes manually.
Was generative AI tooling used to co-author this PR?
Claude Code, Opus 4.7
{pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.