With the changes proposed in AIP-103, the scope of this AIP is changing. Rather than needing to implement a state management system, the tools that AIP-103 will produced will be used. This AIP will aim to shift the paradigm of "Asset watching" to be Asset-aware, something that |
|
Incremental processing is one of the most, it not the most common pattern implement with Airflow. Although external event driven scheduling is supported today in Airflow via AIP-82, incremental polling is not something that has been easy to implement. In more traditional DAG authoring (Sensors, Operators, etc.), users are forced to use XCom or Variables for storing values (watermarks) for incremental processing, or inventing their own solution. In the case of event-driven triggering, it’s even more challenging for users to build their custom incremental processing implementation, due to the lack of XCom support and limitations of Variable s.
There have been several attempts to store state within a child of the BaseEventTrigger to manage incremental processes, while none of these have proven to be effective or robust. This has seriously hampered the ability for the community to build logic to monitor Assets such as object stores, SQL databases, and other non-queue/stream-based Assets. With AIP-103, this state store will be developed and available to use as part of this AIP.
For Triggers built for "Asset watching", it is helpful, if not essential to persist some state. This AIP will provide an interface for using the state store built by AIP-103 for "Asset watching".
At a high level, we propose to make the following changes:
BaseEventTrigger 's Asset-aware.BaseEventTrigger to include methods allowing users to store and retrieve state for an Asset. This solves one of the most glaring problems with building Triggers compatible with "Asset-watching", or event-driven scheduling; the inability to persist and retrieve state for an Asset. Without a way to retrieve the state for an Asset , it's nearly impossible to do things like monitor an S3 bucket for new files landing or handle the addition/removal of a new row to a SQL database. Despite being one of the most touted features of Airflow 3.0, the community has been very slow to develop and distribute Event Triggers to be used for "Asset-watching". This AIP aims to address this problem using the work laid in AIP-103.
Please note that all content below this needs to be updated to reflect the changes that AIP-103 will enabled this AIP to implemented. |
One of the most common use-cases for event-driven scheduling will most likely be “watching” an object store for changes. Ideally, each time that an AssetWatcher ’s Trigger runs, it should not re-scan the entire bucket. The workflow would look something like this:
Another common use-case for event-driven scheduling is “watching” tables in relational databases; we’ll use Postgres as an example. Outside of traditional CDC, it’s common for data teams to use an updated column in a Postgres database to upsert data. Using the StateVariable approach, Airflow users can use the following workflow. This should feel quite similar to the workflow for “watching” an S3 Bucket; that’s intentional, as we’re trying to implement a repeatable pattern.
table_last_updated_at StateVariable.Below is an example of a Trigger that executes a SQL query to incrementally read data, with a watermark. Implementing something like the new_watermark and get_watermark methods is not required; it just shows an example of how StateVariable can be used.
from airflow.sdk import StateVariable
class SQLIncrementalQueryTrigger(BaseEventTrigger):
state_variable_name = "table_last_updated_at"
...
@property
def new_watermark(self):
return datetime.now()
@property
def get_watermark(self):
return StateVariable.get(self.state_variable_name)
async def run(self):
while True:
results = conn.get_records("SELECT * FROM table WHERE updated_at > '%s'", self.get_watermark())
if results:
StateVariable.set(key=self.state_variable_name, value=self.new_watermark)
yield TriggerEvent({"status": "success", "results": results})
break
else:
await asyncio.sleep(self.poke_interval) |
Allow for an Airflow-supported methodology for persisting state and unblocking the development of Event Triggers for Airflow users interested in "Asset-watching".
There is one theorized downside; Airflow users leveraging the StateVariable model as a sort of key-value store outside of an Event Trigger. However, this is not something that is overly concerning. It would be much more likely for Airflow users to abuse the Variable model instead. Along with this are the general downsides to added complexity, but those are minimal with this proposal.
DAG Authors: these users will now have access to a tool that makes authoring Triggers, Sensors, and Tasks used to orchestrate incremental processes more accessible and unlocks the ability to further build out event-driven logic.
Deployment Managers: introducing a pattern with a pluggable backend may provide deployment managers an additional component of their Airflow “stack” to stand up and manage. This will also require a DB migration, which is outlined below.
Current users who don't use incremental event triggers are unaffected by this change. However, this new feature requires a DB migration, since a new model is being added. The only changes needed in this case would be the addition of a new table.
There are not breaking changes included as part of this AIP. Added the StateVariable model will require a DB migration, but forces no breaking changes upon users.
State , StateVariable , ProcessState , Watermark , and more.AssetWatcher is in no way tied to the Asset itself. This disconnect makes the naming and implementation of this functionality challenging. Should this be something that is tied to an Asset? Should it be only applicable at the Trigger-level? Overall, the goal of this AIP is to make event-driven scheduling more intuitive for Airflow users. This AIP will be considered “done” when the PR creates the model and the pluggable backend is merged and the solution is well-documented.