-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CDK: Emit control message on config mutation (#19428)
- Loading branch information
1 parent
b78fdad
commit 3b15f9e
Showing
8 changed files
with
368 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# | ||
# Copyright (c) 2022 Airbyte, Inc., all rights reserved. | ||
# | ||
|
||
from __future__ import ( # Used to evaluate type hints at runtime, a NameError: name 'ConfigObserver' is not defined is thrown otherwise | ||
annotations, | ||
) | ||
|
||
import time | ||
from typing import Any, List, MutableMapping | ||
|
||
from airbyte_cdk.models import AirbyteControlConnectorConfigMessage, AirbyteControlMessage, AirbyteMessage, OrchestratorType, Type | ||
|
||
|
||
class ObservedDict(dict): | ||
def __init__(self, non_observed_mapping: MutableMapping, observer: ConfigObserver, update_on_unchanged_value=True) -> None: | ||
non_observed_mapping = non_observed_mapping.copy() | ||
self.observer = observer | ||
self.update_on_unchanged_value = update_on_unchanged_value | ||
for item, value in non_observed_mapping.items(): | ||
# Observe nested dicts | ||
if isinstance(value, MutableMapping): | ||
non_observed_mapping[item] = ObservedDict(value, observer) | ||
|
||
# Observe nested list of dicts | ||
if isinstance(value, List): | ||
for i, sub_value in enumerate(value): | ||
if isinstance(sub_value, MutableMapping): | ||
value[i] = ObservedDict(sub_value, observer) | ||
super().__init__(non_observed_mapping) | ||
|
||
def __setitem__(self, item: Any, value: Any): | ||
"""Override dict.__setitem__ by: | ||
1. Observing the new value if it is a dict | ||
2. Call observer update if the new value is different from the previous one | ||
""" | ||
previous_value = self.get(item) | ||
if isinstance(value, MutableMapping): | ||
value = ObservedDict(value, self.observer) | ||
if isinstance(value, List): | ||
for i, sub_value in enumerate(value): | ||
if isinstance(sub_value, MutableMapping): | ||
value[i] = ObservedDict(sub_value, self.observer) | ||
super(ObservedDict, self).__setitem__(item, value) | ||
if self.update_on_unchanged_value or value != previous_value: | ||
self.observer.update() | ||
|
||
|
||
class ConfigObserver: | ||
"""This class is made to track mutations on ObservedDict config. | ||
When update is called a CONNECTOR_CONFIG control message is emitted on stdout. | ||
""" | ||
|
||
def set_config(self, config: ObservedDict) -> None: | ||
self.config = config | ||
|
||
def update(self) -> None: | ||
self._emit_airbyte_control_message() | ||
|
||
def _emit_airbyte_control_message(self) -> None: | ||
control_message = AirbyteControlMessage( | ||
type=OrchestratorType.CONNECTOR_CONFIG, | ||
emitted_at=time.time() * 1000, | ||
connectorConfig=AirbyteControlConnectorConfigMessage(config=self.config), | ||
) | ||
airbyte_message = AirbyteMessage(type=Type.CONTROL, control=control_message) | ||
print(airbyte_message.json(exclude_unset=True)) | ||
|
||
|
||
def observe_connector_config(non_observed_connector_config: MutableMapping[str, Any]): | ||
if isinstance(non_observed_connector_config, ObservedDict): | ||
raise ValueError("This connector configuration is already observed") | ||
connector_config_observer = ConfigObserver() | ||
observed_connector_config = ObservedDict(non_observed_connector_config, connector_config_observer) | ||
connector_config_observer.set_config(observed_connector_config) | ||
return observed_connector_config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.