Skip to content

feat: Message data classes - #284

Open
chrisk314 wants to merge 9 commits into
mainfrom
feat/message-data-classes
Open

feat: Message data classes#284
chrisk314 wants to merge 9 commits into
mainfrom
feat/message-data-classes

Conversation

@chrisk314

@chrisk314 chrisk314 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements #102: feat: Base component for external communication (#102).

Plugboard's existing DataReader/DataWriter classes handle chunking, buffering, and field-based IO for file and databasesources, but there was no equivalent for message broker infrastructure. This PR introduces MessageDataReader and MessageDataWriter abstract base classes that provide the same field-based IO pattern for pub/sub messaging — with connection lifecycle management, automatic reconnection with exponential backoff, retry logic, message acknowledgment, and chunked/buffered reads and writes. Three concrete implementations are included: Google Cloud PubSub, AWS SQS/SNS, and Apache Kafka. No cloud infrastructure is provisioned yet; all tests run against mocks and will be iterated against real infrastructure later.

Changes

  • MessageDataReader base class — abstract interface for reading from message brokers with _connect, _disconnect, _receive,
    _convert, _ack methods and built-in retry/reconnection
  • MessageDataWriter base class — abstract interface for writing to message brokers with _connect, _disconnect, _send, _convert
    methods and built-in retry/reconnection
  • GCP PubSub implementation (GCPPubSubDataReader/GCPPubSubDataWriter) using google-cloud-pubsub
  • AWS SQS/SNS implementation (AWSSQSDataReader/AWSSNSDataWriter) using aioboto3
  • Kafka implementation (KafkaDataReader/KafkaDataWriter) using aiokafka
  • Message broker exception hierarchy (MessageBrokerConnectionError, MessageBrokerTransientError, MessageBrokerPermanentError)
  • Settings additions for GCP PubSub, AWS, and Kafka configuration via environment variables
  • Optional dependencies added to pyproject.toml (gcp-pubsub, aws-messaging, kafka)
  • 72 unit tests covering base class behavior, retry logic, connection lifecycle, and all three broker implementations

fsspec license metadata is not detectable by licensecheck, causing
CI failures. Add to ignore list since it's BSD-3-Clause licensed.
Implements issue #102: Base component for external communication via
pub/sub message broker infrastructure.

New base classes:
- MessageDataReader: Abstract base for reading data from message brokers
  with connection management, reconnection with exponential backoff,
  retry logic, message acknowledgment, and chunked/buffered reading.
- MessageDataWriter: Abstract base for writing data to message brokers
  with connection management, reconnection, retry logic, and
  chunked/buffered writing.

Concrete implementations:
- GCPPubSubDataReader/Writer: Google Cloud PubSub
- AWSSQSDataReader/AWSSNSDataWriter: AWS SQS/SNS
- KafkaDataReader/Writer: Apache Kafka

Also includes:
- Message broker exceptions (ConnectionError, TransientError, PermanentError)
- Settings for GCP PubSub, AWS, and Kafka
- Optional dependencies in pyproject.toml
- Proposal document with design rationale
- Comprehensive unit tests (72 new tests)
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Benchmark comparison for fa9a1b92 (base) vs e14a0fae (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     538.2940 (1.0)      550.3755 (1.00)     543.8897 (1.0)      5.3367 (2.22)     545.2340 (1.0)      9.4054 (2.37)          3;0  1.8386 (1.0)           5           1
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         543.6806 (1.01)     549.3609 (1.0)      546.7065 (1.01)     2.4078 (1.0)      545.9489 (1.00)     3.9692 (1.0)           2;0  1.8291 (0.99)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

- Fix ruff lint errors: import sorting, unused imports, S110 noqa comments
- Fix ruff format errors in gcp_pubsub_io.py
- Fix mypy overlap errors: remove duplicate fields from ArgsDict TypedDicts
- Fix mypy multiple values error: use kwargs.setdefault instead of pop
- Remove untracked test data files causing lint failures
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Benchmark comparison for fa9a1b92 (base) vs e538c242 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         378.6095 (1.0)      381.9872 (1.0)      380.3807 (1.0)      1.4510 (1.0)      380.8602 (1.0)      2.4960 (1.0)           2;0  2.6289 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     380.9969 (1.01)     387.2179 (1.01)     383.3493 (1.01)     2.6439 (1.82)     381.8112 (1.00)     3.9492 (1.58)          1;0  2.6086 (0.99)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

Increase connection establishment sleep in _ZMQPipelineConnectorProxy
from 0.1s to 0.5s to allow the proxy subprocess's SUB socket
subscription to propagate to XPUB before the sender starts publishing
(ZMQ slow joiner problem). Also mark the test as flaky with 3 reruns
following the existing pattern used elsewhere in the repo.

Fixes: test_process_with_components_run[RayProcess-zmq_connector_cls-zmq_pubsub_proxy=True-10-2.0]
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Benchmark comparison for 7b0cbeda (base) vs e49d472e (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         286.1344 (1.0)      297.6967 (1.0)      292.9123 (1.0)      4.6218 (1.97)     294.8739 (1.0)      6.6802 (2.40)          2;0  3.4140 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     295.0680 (1.03)     301.3671 (1.01)     297.8813 (1.02)     2.3407 (1.0)      297.1355 (1.01)     2.7794 (1.0)           2;0  3.3570 (0.98)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

- Fix invalid-raise errors in message_reader.py and message_writer.py
  by initializing last_exception with a non-None default instead of
  Optional[Exception]
- Remove PublisherClient.close() call in gcp_pubsub_io.py (method does
  not exist on the client); just set reference to None for GC
- Update test to match new disconnect behavior
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Benchmark comparison for 7b0cbeda (base) vs d315dd07 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     534.4430 (1.0)      539.0566 (1.0)      536.5269 (1.0)      1.8247 (1.0)      535.9234 (1.0)      2.7265 (1.0)           2;0  1.8638 (1.0)           5           1
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         538.3621 (1.01)     549.1566 (1.02)     544.6404 (1.02)     4.0247 (2.21)     545.0155 (1.02)     4.7870 (1.76)          2;0  1.8361 (0.99)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

The design proposal is not tracked in the repo. Added to .gitignore
to prevent accidental re-commit.
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Benchmark comparison for 7b0cbeda (base) vs 0fa21c58 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     527.9234 (1.0)      542.6921 (1.0)      537.0849 (1.0)      5.5841 (1.28)     537.6015 (1.0)      5.9359 (1.0)           2;0  1.8619 (1.0)           5           1
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         540.4164 (1.02)     550.3291 (1.01)     546.0575 (1.02)     4.3785 (1.0)      548.3933 (1.02)     7.3029 (1.23)          1;0  1.8313 (0.98)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant