From d00d60a377a32f9bb0bfdbc30cc120847ee456b7 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 19 Mar 2026 14:07:50 -0600 Subject: [PATCH 01/19] add datastream websocket client --- .fernignore | 1 + poetry.lock | 138 +++++- pyproject.toml | 1 + src/schematic/datastream/__init__.py | 14 + src/schematic/datastream/types.py | 64 +++ src/schematic/datastream/websocket_client.py | 346 +++++++++++++ tests/datastream/test_websocket_client.py | 480 +++++++++++++++++++ 7 files changed, 1038 insertions(+), 6 deletions(-) create mode 100644 src/schematic/datastream/__init__.py create mode 100644 src/schematic/datastream/types.py create mode 100644 src/schematic/datastream/websocket_client.py create mode 100644 tests/datastream/test_websocket_client.py diff --git a/.fernignore b/.fernignore index 35c0aa1..e79778f 100644 --- a/.fernignore +++ b/.fernignore @@ -13,6 +13,7 @@ src/schematic/cache.py src/schematic/event_buffer.py src/schematic/http_client.py src/schematic/logging.py +src/schematic/datastream/ src/schematic/webhook_utils/ src/schematic/webhooks/verification.py tests/custom/ diff --git a/poetry.lock b/poetry.lock index 83fdc8b..bea4166 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "annotated-types" @@ -6,6 +6,7 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -20,6 +21,7 @@ version = "4.5.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"}, {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"}, @@ -33,7 +35,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21.0b1) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -42,6 +44,7 @@ version = "2026.2.25" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, @@ -53,6 +56,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -64,6 +69,8 @@ version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, @@ -81,6 +88,7 @@ version = "2.1.2" description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"}, {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"}, @@ -95,6 +103,7 @@ version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, @@ -106,6 +115,7 @@ version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, @@ -127,6 +137,7 @@ version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, @@ -139,7 +150,7 @@ httpcore = "==1.*" idna = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -151,6 +162,7 @@ version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, @@ -165,6 +177,7 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, @@ -176,6 +189,7 @@ version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, @@ -229,6 +243,7 @@ version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, @@ -240,6 +255,7 @@ version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, @@ -251,6 +267,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -266,6 +283,7 @@ version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, @@ -278,7 +296,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" @@ -286,6 +304,7 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -398,6 +417,7 @@ version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, @@ -420,6 +440,7 @@ version = "0.23.8" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, @@ -438,6 +459,7 @@ version = "3.6.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, @@ -458,6 +480,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -472,6 +495,7 @@ version = "0.11.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"}, {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"}, @@ -499,6 +523,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -510,6 +535,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -521,6 +547,8 @@ version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, @@ -577,6 +605,7 @@ version = "2.9.0.20241206" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, @@ -588,12 +617,109 @@ version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] +[[package]] +name = "websockets" +version = "13.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, + {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, + {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, + {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, + {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, + {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, + {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, + {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, + {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, + {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, + {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, + {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, + {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, + {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, + {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, + {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, + {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, + {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, + {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, + {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, + {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, + {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, + {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, + {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, + {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, + {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, + {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, + {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, + {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, + {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, + {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, + {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, + {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, + {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, + {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, + {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, + {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, + {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, + {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, + {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, + {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, +] + [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.8" -content-hash = "bcf31a142c86d9e556553c8c260a93b563ac64a043076dbd48b26111d422c26e" +content-hash = "4938beb3198ee4d1c0088267e91cd608c926c85825b39afdd9ab5b160a2a8df1" diff --git a/pyproject.toml b/pyproject.toml index 0ef3755..63a5cec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ httpx = ">=0.21.2" pydantic = ">= 1.9.2" pydantic-core = ">=2.18.2" typing_extensions = ">= 4.0.0" +websockets = ">=10.0" [tool.poetry.group.dev.dependencies] mypy = "==1.13.0" diff --git a/src/schematic/datastream/__init__.py b/src/schematic/datastream/__init__.py new file mode 100644 index 0000000..b777f85 --- /dev/null +++ b/src/schematic/datastream/__init__.py @@ -0,0 +1,14 @@ +from .types import DataStreamBaseReq, DataStreamError, DataStreamReq, DataStreamResp, EntityType, MessageType +from .websocket_client import ClientOptions, DatastreamWSClient, convert_api_url_to_websocket_url + +__all__ = [ + "ClientOptions", + "DataStreamBaseReq", + "DataStreamError", + "DataStreamReq", + "DataStreamResp", + "DatastreamWSClient", + "EntityType", + "MessageType", + "convert_api_url_to_websocket_url", +] diff --git a/src/schematic/datastream/types.py b/src/schematic/datastream/types.py new file mode 100644 index 0000000..534fb9c --- /dev/null +++ b/src/schematic/datastream/types.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import enum +from dataclasses import dataclass, field +from typing import Any, Dict, Optional + + +class EntityType(str, enum.Enum): + COMPANY = "rulesengine.Company" + COMPANIES = "rulesengine.Companies" + USER = "rulesengine.User" + USERS = "rulesengine.Users" + FLAG = "rulesengine.Flag" + FLAGS = "rulesengine.Flags" + + +class MessageType(str, enum.Enum): + FULL = "full" + PARTIAL = "partial" + DELETE = "delete" + ERROR = "error" + UNKNOWN = "unknown" + + +@dataclass +class DataStreamReq: + """Request message sent to the datastream.""" + + entity_type: EntityType + keys: Optional[Dict[str, str]] = None + + def to_dict(self) -> Dict[str, Any]: + d: Dict[str, Any] = {"entity_type": self.entity_type.value} + if self.keys is not None: + d["keys"] = self.keys + return d + + +@dataclass +class DataStreamBaseReq: + """Wrapper around DataStreamReq — the wire format expected by the server.""" + + data: DataStreamReq + + def to_dict(self) -> Dict[str, Any]: + return {"data": self.data.to_dict()} + + +@dataclass +class DataStreamResp: + """Response message received from the datastream.""" + + data: Any + entity_type: str + message_type: str + + +@dataclass +class DataStreamError: + """Error message received from the datastream.""" + + error: str + keys: Optional[Dict[str, str]] = None + entity_type: Optional[EntityType] = None diff --git a/src/schematic/datastream/websocket_client.py b/src/schematic/datastream/websocket_client.py new file mode 100644 index 0000000..3cca4cd --- /dev/null +++ b/src/schematic/datastream/websocket_client.py @@ -0,0 +1,346 @@ +from __future__ import annotations + +# Note: This client is designed for server-side async environments only. + +import asyncio +import json +import logging +import random +from dataclasses import dataclass +from typing import AsyncIterator, Awaitable, Callable, Dict, Optional, Protocol, Union +from urllib.parse import urlparse, urlunparse + +import websockets + +from .types import DataStreamBaseReq, DataStreamResp + + +class _WebSocketProtocol(Protocol): + """Structural interface for the websocket connection object.""" + + async def send(self, message: Union[str, bytes]) -> None: ... + + async def close(self) -> None: ... + + def __aiter__(self) -> AsyncIterator[Union[str, bytes]]: ... + +# Connection timing constants (seconds) +WRITE_WAIT = 10.0 +PONG_WAIT = 60.0 +PING_PERIOD = (PONG_WAIT * 9) / 10 # 54 seconds +CONNECTION_TIMEOUT = 30.0 + +# Reconnection constants +MAX_RECONNECT_ATTEMPTS = 10 +MIN_RECONNECT_DELAY = 1.0 # seconds +MAX_RECONNECT_DELAY = 30.0 # seconds + +MessageHandlerFunc = Callable[[DataStreamResp], Awaitable[None]] +ConnectionReadyHandlerFunc = Callable[[], Awaitable[None]] + + +def convert_api_url_to_websocket_url(api_url: str) -> str: + """Convert an HTTP API URL to a WebSocket datastream URL. + + Examples: + https://api.schematichq.com -> wss://datastream.schematichq.com/datastream + https://api.staging.x.com -> wss://datastream.staging.x.com/datastream + https://custom.example.com -> wss://custom.example.com/datastream + http://localhost:8080 -> ws://localhost:8080/datastream + """ + parsed = urlparse(api_url) + + if parsed.scheme == "https": + scheme = "wss" + elif parsed.scheme == "http": + scheme = "ws" + else: + raise ValueError(f"Unsupported scheme: {parsed.scheme!r} (must be http or https)") + + # Replace 'api' subdomain with 'datastream' if present + hostname = parsed.hostname or "" + parts = hostname.split(".") + if len(parts) > 1 and parts[0] == "api": + parts[0] = "datastream" + hostname = ".".join(parts) + + netloc = f"{hostname}:{parsed.port}" if parsed.port else hostname + return urlunparse((scheme, netloc, "/datastream", "", "", "")) + + +@dataclass +class ClientOptions: + """Configuration for DatastreamWSClient.""" + + # Required + url: str + api_key: str + message_handler: MessageHandlerFunc + logger: logging.Logger + + # Optional + connection_ready_handler: Optional[ConnectionReadyHandlerFunc] = None + max_reconnect_attempts: int = MAX_RECONNECT_ATTEMPTS + min_reconnect_delay: float = MIN_RECONNECT_DELAY + max_reconnect_delay: float = MAX_RECONNECT_DELAY + + # Event callbacks — called on state transitions + on_connected: Optional[Callable[[], None]] = None + on_disconnected: Optional[Callable[[], None]] = None + on_ready: Optional[Callable[[], None]] = None + on_not_ready: Optional[Callable[[], None]] = None + on_error: Optional[Callable[[Exception], None]] = None + + +class DatastreamWSClient: + """WebSocket client for the Schematic datastream with automatic reconnection. + + Connects to the Schematic datastream, delivers incoming messages to the + provided ``message_handler``, and transparently reconnects with exponential + backoff whenever the connection drops. + + Usage:: + + async def handle_message(msg: DataStreamResp) -> None: + print(msg) + + client = DatastreamWSClient(ClientOptions( + url="https://api.schematichq.com", + api_key="your-api-key", + message_handler=handle_message, + logger=logging.getLogger(__name__), + )) + client.start() + # ... later: + await client.close() + """ + + def __init__(self, options: ClientOptions) -> None: + if not options.url: + raise ValueError("url is required") + if not options.api_key: + raise ValueError("api_key is required") + if not options.message_handler: + raise ValueError("message_handler is required") + + # Auto-convert HTTP(S) URLs to WebSocket URLs + if options.url.startswith(("http://", "https://")): + self._url = convert_api_url_to_websocket_url(options.url) + else: + self._url = options.url + + self._headers: Dict[str, str] = {"X-Schematic-Api-Key": options.api_key} + self._logger = options.logger + self._message_handler = options.message_handler + self._connection_ready_handler = options.connection_ready_handler + self._max_reconnect_attempts = options.max_reconnect_attempts + self._min_reconnect_delay = options.min_reconnect_delay + self._max_reconnect_delay = options.max_reconnect_delay + + # Event callbacks + self._on_connected = options.on_connected + self._on_disconnected = options.on_disconnected + self._on_ready = options.on_ready + self._on_not_ready = options.on_not_ready + self._on_error = options.on_error + + # Connection state + self._ws: Optional[_WebSocketProtocol] = None + self._connected: bool = False + self._ready: bool = False + + # Control state + self._should_reconnect: bool = False + self._reconnect_attempts: int = 0 + self._task: Optional[asyncio.Task[None]] = None + + def start(self) -> None: + """Begin the WebSocket connection loop as a background asyncio task.""" + self._should_reconnect = True + self._reconnect_attempts = 0 + self._task = asyncio.ensure_future(self._connect_and_read()) + + def is_connected(self) -> bool: + """Return whether the WebSocket is currently connected.""" + return self._connected + + def is_ready(self) -> bool: + """Return whether the client is connected and fully initialised.""" + return self._ready and self._connected + + async def send_message(self, message: DataStreamBaseReq) -> None: + """Send a message over the WebSocket connection. + + Raises ``RuntimeError`` if the connection is not available or the send + times out after ``WRITE_WAIT`` seconds. + """ + if not self.is_connected() or self._ws is None: + raise RuntimeError("WebSocket connection is not available") + + payload = json.dumps(message.to_dict()) + try: + await asyncio.wait_for(self._ws.send(payload), timeout=WRITE_WAIT) + except asyncio.TimeoutError: + raise RuntimeError("Write timeout") + + async def close(self) -> None: + """Gracefully close the connection and stop the reconnection loop.""" + self._logger.info("Closing WebSocket connection") + + self._should_reconnect = False + self._set_ready(False) + self._set_connected(False) + + if self._ws is not None: + try: + await self._ws.close() + except Exception: + pass + self._ws = None + + if self._task is not None: + self._task.cancel() + try: + await self._task + except (asyncio.CancelledError, Exception): + pass + self._task = None + + # ------------------------------------------------------------------ + # Internal connection loop + # ------------------------------------------------------------------ + + async def _connect_and_read(self) -> None: + while self._should_reconnect: + try: + async with websockets.connect( + self._url, + extra_headers=self._headers, + open_timeout=CONNECTION_TIMEOUT, + ping_interval=PING_PERIOD, + ping_timeout=PONG_WAIT, + ) as ws: + self._ws = ws + self._reconnect_attempts = 0 + self._set_connected(True) + + # Run the ready handler before marking the client ready + if self._connection_ready_handler is not None: + try: + await self._connection_ready_handler() + self._logger.debug("Connection ready handler completed successfully") + except Exception as err: + self._logger.error(f"Connection ready handler failed: {err}") + continue + + self._set_ready(True) + self._logger.debug("WebSocket client is ready") + + async for raw_message in ws: + await self._handle_message(raw_message) + + self._logger.info("WebSocket connection closed") + + except asyncio.CancelledError: + break + + except Exception as err: + self._reconnect_attempts += 1 + self._logger.warning( + f"WebSocket connection failed: {err}, " + f"attempt {self._reconnect_attempts}/{self._max_reconnect_attempts}" + ) + + if self._reconnect_attempts >= self._max_reconnect_attempts: + self._logger.error("Max reconnection attempts reached") + if self._on_error is not None: + self._on_error(Exception("Max reconnection attempts reached")) + break + + finally: + self._set_connected(False) + self._set_ready(False) + self._ws = None + + if not self._should_reconnect: + break + + delay = self._calculate_backoff_delay(self._reconnect_attempts) + self._logger.debug(f"Waiting {delay:.1f}s before reconnecting...") + try: + await asyncio.sleep(delay) + except asyncio.CancelledError: + break + + # ------------------------------------------------------------------ + # Message handling + # ------------------------------------------------------------------ + + async def _handle_message(self, raw_message: Union[str, bytes]) -> None: + try: + if isinstance(raw_message, bytes): + message_str = raw_message.decode("utf-8") + else: + message_str = str(raw_message) + + try: + data = json.loads(message_str) + except json.JSONDecodeError as err: + if self._on_error is not None: + self._on_error(Exception(f"Failed to parse datastream message: {err}")) + return + + message = DataStreamResp( + data=data.get("data"), + entity_type=data.get("entity_type", ""), + message_type=data.get("message_type", ""), + ) + + try: + await self._message_handler(message) + except Exception as err: + if self._on_error is not None: + self._on_error(Exception(f"Message handler error: {err}")) + + except Exception as err: + if self._on_error is not None: + self._on_error(err) + + # ------------------------------------------------------------------ + # State management + # ------------------------------------------------------------------ + + def _set_connected(self, connected: bool) -> None: + was_connected = self._connected + self._connected = connected + + if not connected: + self._ready = False + + if was_connected != connected: + self._logger.debug(f"Connection state changed: {connected}") + if connected: + if self._on_connected is not None: + self._on_connected() + else: + if self._on_disconnected is not None: + self._on_disconnected() + + def _set_ready(self, ready: bool) -> None: + was_ready = self._ready + self._ready = ready + + if was_ready != ready: + self._logger.debug(f"Ready state changed: {ready}") + if ready: + if self._on_ready is not None: + self._on_ready() + else: + if self._on_not_ready is not None: + self._on_not_ready() + + def _calculate_backoff_delay(self, attempt: int) -> float: + """Exponential backoff with jitter, capped at max_reconnect_delay.""" + jitter = random.uniform(0, self._min_reconnect_delay) + delay = (2 ** (attempt - 1)) * self._min_reconnect_delay + jitter + return min(delay, self._max_reconnect_delay + jitter) diff --git a/tests/datastream/test_websocket_client.py b/tests/datastream/test_websocket_client.py new file mode 100644 index 0000000..d7ff10a --- /dev/null +++ b/tests/datastream/test_websocket_client.py @@ -0,0 +1,480 @@ +from __future__ import annotations + +import asyncio +import json +import logging +from contextlib import asynccontextmanager +from typing import AsyncIterator, List, Optional +from unittest.mock import patch + +import pytest + +from schematic.datastream.types import DataStreamBaseReq, DataStreamReq, DataStreamResp, EntityType +from schematic.datastream.websocket_client import ( + ClientOptions, + DatastreamWSClient, + convert_api_url_to_websocket_url, +) + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# Mock helpers +# --------------------------------------------------------------------------- + + +class MockWebSocket: + """Fake WebSocket that yields a fixed list of messages then stops. + + Set ``block_on_empty=True`` to keep the connection open after all messages + are consumed — useful for tests that need to inspect state while connected. + Call ``.close()`` to unblock. + """ + + def __init__(self, messages: Optional[List[str]] = None, block_on_empty: bool = False) -> None: + self._messages = messages or [] + self._index = 0 + self._block_on_empty = block_on_empty + self._close_event: asyncio.Event = asyncio.Event() + self.sent: List[str] = [] + self.closed = False + + async def send(self, message: str | bytes) -> None: + self.sent.append(message.decode() if isinstance(message, bytes) else message) + + async def close(self) -> None: + self.closed = True + self._close_event.set() + + def __aiter__(self) -> AsyncIterator[str]: + return self + + async def __anext__(self) -> str: + if self._index < len(self._messages): + msg = self._messages[self._index] + self._index += 1 + return msg + if self._block_on_empty: + await self._close_event.wait() + raise StopAsyncIteration + + +class _AlwaysFailConnect: + """Mimics websockets.connect but always raises on __aenter__.""" + + def __call__(self, *args, **kwargs) -> _AlwaysFailConnect: + return self + + async def __aenter__(self) -> None: + raise ConnectionError("connection refused") + + async def __aexit__(self, *args) -> None: + pass + + +def make_connect(ws: MockWebSocket): + """Return a mock for websockets.connect that yields the given MockWebSocket.""" + + @asynccontextmanager + async def _connect(*args, **kwargs): + yield ws + + return _connect + + +def make_client( + messages: Optional[List[str]] = None, + ws: Optional[MockWebSocket] = None, + **kwargs, +) -> tuple[DatastreamWSClient, MockWebSocket, List[DataStreamResp]]: + """Build a DatastreamWSClient backed by a MockWebSocket. + + Extra kwargs are forwarded to ClientOptions, allowing callbacks and other + options to be set per-test. + """ + if ws is None: + ws = MockWebSocket(messages or []) + + received: List[DataStreamResp] = [] + + async def handler(msg: DataStreamResp) -> None: + received.append(msg) + + client = DatastreamWSClient( + ClientOptions( + url="wss://test.example.com/datastream", + api_key="test-key", + message_handler=handler, + logger=logger, + min_reconnect_delay=0.0, + max_reconnect_delay=0.0, + **kwargs, + ) + ) + return client, ws, received + + +async def wait_until(condition, timeout: float = 2.0, poll: float = 0.01) -> None: + """Poll until condition() is True or timeout is reached.""" + + async def _poll(): + while not condition(): + await asyncio.sleep(poll) + + await asyncio.wait_for(_poll(), timeout=timeout) + + +# --------------------------------------------------------------------------- +# convert_api_url_to_websocket_url +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "api_url,expected", + [ + ("https://api.schematichq.com", "wss://datastream.schematichq.com/datastream"), + ("https://api.staging.schematichq.com", "wss://datastream.staging.schematichq.com/datastream"), + ("https://custom.example.com", "wss://custom.example.com/datastream"), + ("http://localhost:8080", "ws://localhost:8080/datastream"), + ("http://localhost", "ws://localhost/datastream"), + ], +) +def test_convert_api_url(api_url: str, expected: str) -> None: + assert convert_api_url_to_websocket_url(api_url) == expected + + +def test_convert_api_url_unsupported_scheme() -> None: + with pytest.raises(ValueError, match="Unsupported scheme"): + convert_api_url_to_websocket_url("ftp://example.com") + + +# --------------------------------------------------------------------------- +# Constructor validation +# --------------------------------------------------------------------------- + + +def test_init_missing_url() -> None: + async def handler(msg): pass + + with pytest.raises(ValueError, match="url is required"): + DatastreamWSClient(ClientOptions(url="", api_key="key", message_handler=handler, logger=logger)) + + +def test_init_missing_api_key() -> None: + async def handler(msg): pass + + with pytest.raises(ValueError, match="api_key is required"): + DatastreamWSClient(ClientOptions(url="wss://example.com", api_key="", message_handler=handler, logger=logger)) + + +def test_init_missing_message_handler() -> None: + with pytest.raises(ValueError, match="message_handler is required"): + DatastreamWSClient( + ClientOptions(url="wss://example.com", api_key="key", message_handler=None, logger=logger) + ) + + +def test_init_converts_http_url() -> None: + async def handler(msg): pass + + client = DatastreamWSClient( + ClientOptions(url="https://api.schematichq.com", api_key="key", message_handler=handler, logger=logger) + ) + assert client._url == "wss://datastream.schematichq.com/datastream" + + +# --------------------------------------------------------------------------- +# send_message +# --------------------------------------------------------------------------- + + +async def test_send_message_raises_when_not_connected() -> None: + client, _, _ = make_client() + req = DataStreamBaseReq(data=DataStreamReq(entity_type=EntityType.COMPANY)) + + with pytest.raises(RuntimeError, match="not available"): + await client.send_message(req) + + +async def test_send_message_sends_json_when_connected() -> None: + ws = MockWebSocket(block_on_empty=True) + connected = asyncio.Event() + client, ws, _ = make_client(ws=ws, on_connected=lambda: connected.set()) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await asyncio.wait_for(connected.wait(), timeout=2.0) + + req = DataStreamBaseReq(data=DataStreamReq(entity_type=EntityType.COMPANY)) + await client.send_message(req) + + assert len(ws.sent) == 1 + assert json.loads(ws.sent[0]) == {"data": {"entity_type": "rulesengine.Company"}} + + await client.close() + + +# --------------------------------------------------------------------------- +# Message handling +# --------------------------------------------------------------------------- + + +async def test_string_message_delivered_to_handler() -> None: + msg = json.dumps({"entity_type": "rulesengine.Company", "message_type": "full", "data": {"id": "123"}}) + client, ws, received = make_client(messages=[msg]) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(lambda: len(received) == 1) + await client.close() + + assert received[0].entity_type == "rulesengine.Company" + assert received[0].message_type == "full" + assert received[0].data == {"id": "123"} + + +async def test_bytes_message_delivered_to_handler() -> None: + payload = json.dumps({"entity_type": "rulesengine.Flag", "message_type": "full", "data": None}) + ws = MockWebSocket(messages=[payload.encode()]) + client, ws, received = make_client(ws=ws) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(lambda: len(received) == 1) + await client.close() + + assert received[0].entity_type == "rulesengine.Flag" + + +async def test_invalid_json_calls_on_error() -> None: + errors: List[Exception] = [] + client, ws, _ = make_client(messages=["not-valid-json"], on_error=errors.append) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(lambda: len(errors) > 0) + await client.close() + + assert "Failed to parse" in str(errors[0]) + + +async def test_message_handler_exception_calls_on_error() -> None: + errors: List[Exception] = [] + + async def bad_handler(msg: DataStreamResp) -> None: + raise ValueError("handler blew up") + + msg = json.dumps({"entity_type": "rulesengine.Company", "message_type": "full", "data": None}) + ws = MockWebSocket(messages=[msg]) + client = DatastreamWSClient( + ClientOptions( + url="wss://test.example.com/datastream", + api_key="key", + message_handler=bad_handler, + logger=logger, + min_reconnect_delay=0.0, + max_reconnect_delay=0.0, + on_error=errors.append, + ) + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(lambda: len(errors) > 0) + await client.close() + + assert "Message handler error" in str(errors[0]) + + +# --------------------------------------------------------------------------- +# State callbacks +# --------------------------------------------------------------------------- + + +async def test_on_connected_and_on_ready_fired() -> None: + connected_calls: List[bool] = [] + ready_calls: List[bool] = [] + + ws = MockWebSocket(block_on_empty=True) + client, ws, _ = make_client( + ws=ws, + on_connected=lambda: connected_calls.append(True), + on_ready=lambda: ready_calls.append(True), + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(client.is_ready) + + assert connected_calls == [True] + assert ready_calls == [True] + assert client.is_connected() + assert client.is_ready() + + await client.close() + + +async def test_on_disconnected_and_on_not_ready_fired_on_close() -> None: + disconnected_calls: List[bool] = [] + not_ready_calls: List[bool] = [] + + ws = MockWebSocket(block_on_empty=True) + client, ws, _ = make_client( + ws=ws, + on_disconnected=lambda: disconnected_calls.append(True), + on_not_ready=lambda: not_ready_calls.append(True), + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(client.is_connected) + await client.close() + + assert True in disconnected_calls + assert True in not_ready_calls + assert not client.is_connected() + assert not client.is_ready() + + +# --------------------------------------------------------------------------- +# connection_ready_handler +# --------------------------------------------------------------------------- + + +async def test_connection_ready_handler_called_before_ready() -> None: + order: List[str] = [] + + async def ready_handler() -> None: + order.append("ready_handler") + + ws = MockWebSocket(block_on_empty=True) + client, ws, _ = make_client( + ws=ws, + connection_ready_handler=ready_handler, + on_ready=lambda: order.append("on_ready"), + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await wait_until(client.is_ready) + + assert order == ["ready_handler", "on_ready"] + await client.close() + + +async def test_connection_ready_handler_failure_prevents_ready() -> None: + async def failing_handler() -> None: + raise RuntimeError("setup failed") + + ws = MockWebSocket() + client, ws, _ = make_client( + ws=ws, + connection_ready_handler=failing_handler, + max_reconnect_attempts=1, + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): + client.start() + await asyncio.sleep(0.1) + + assert not client.is_ready() + + +# --------------------------------------------------------------------------- +# Reconnection +# --------------------------------------------------------------------------- + + +async def test_reconnects_after_connection_error() -> None: + connect_calls: List[int] = [] + msg = json.dumps({"entity_type": "rulesengine.Company", "message_type": "full", "data": None}) + success_ws = MockWebSocket(messages=[msg]) + + @asynccontextmanager + async def mock_connect(*args, **kwargs): + connect_calls.append(1) + if len(connect_calls) == 1: + raise ConnectionError("first attempt fails") + yield success_ws + + received: List[DataStreamResp] = [] + + async def handler(m: DataStreamResp) -> None: + received.append(m) + + client = DatastreamWSClient( + ClientOptions( + url="wss://test.example.com/datastream", + api_key="key", + message_handler=handler, + logger=logger, + min_reconnect_delay=0.0, + max_reconnect_delay=0.0, + max_reconnect_attempts=5, + ) + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", mock_connect): + client.start() + await wait_until(lambda: len(received) == 1) + await client.close() + + assert len(connect_calls) >= 2 + assert len(received) == 1 + + +async def test_stops_at_max_reconnect_attempts() -> None: + errors: List[Exception] = [] + + client = DatastreamWSClient( + ClientOptions( + url="wss://test.example.com/datastream", + api_key="key", + message_handler=lambda _: None, + logger=logger, + min_reconnect_delay=0.0, + max_reconnect_delay=0.0, + max_reconnect_attempts=3, + on_error=errors.append, + ) + ) + + with patch("schematic.datastream.websocket_client.websockets.connect", _AlwaysFailConnect()): + client.start() + await wait_until(lambda: len(errors) > 0) + + assert "Max reconnection" in str(errors[0]) + + +# --------------------------------------------------------------------------- +# Backoff delay +# --------------------------------------------------------------------------- + + +def test_backoff_delay_within_bounds() -> None: + client, _, _ = make_client() + + for attempt in range(1, 8): + delay = client._calculate_backoff_delay(attempt) + assert delay >= 0 + assert delay <= client._max_reconnect_delay + client._min_reconnect_delay + + +def test_backoff_delay_does_not_exceed_max() -> None: + async def handler(msg): pass + + client = DatastreamWSClient( + ClientOptions( + url="wss://test.example.com/datastream", + api_key="key", + message_handler=handler, + logger=logger, + min_reconnect_delay=1.0, + max_reconnect_delay=5.0, + ) + ) + + # At high attempt counts, delay should be capped at max + jitter ceiling + delay = client._calculate_backoff_delay(20) + assert delay <= 5.0 + 1.0 From 1b9c7e6e4f6e1710959cea2fe63d03a6cd55eae1 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 08:20:09 -0600 Subject: [PATCH 02/19] add redis cache provider --- src/schematic/cache.py | 71 ---------------- src/schematic/cache/__init__.py | 26 ++++++ src/schematic/cache/local.py | 146 ++++++++++++++++++++++++++++++++ src/schematic/cache/provider.py | 32 +++++++ src/schematic/cache/redis.py | 91 ++++++++++++++++++++ 5 files changed, 295 insertions(+), 71 deletions(-) delete mode 100644 src/schematic/cache.py create mode 100644 src/schematic/cache/__init__.py create mode 100644 src/schematic/cache/local.py create mode 100644 src/schematic/cache/provider.py create mode 100644 src/schematic/cache/redis.py diff --git a/src/schematic/cache.py b/src/schematic/cache.py deleted file mode 100644 index d538c8e..0000000 --- a/src/schematic/cache.py +++ /dev/null @@ -1,71 +0,0 @@ -import time -from collections import OrderedDict -from typing import Generic, Optional -from typing import OrderedDict as OrderedDictType -from typing import TypeVar - -T = TypeVar("T") - -DEFAULT_CACHE_SIZE = 1000 # 1000 items -DEFAULT_CACHE_TTL = 5000 # 5 seconds - - -class CacheProvider(Generic[T]): - def get(self, key: str) -> Optional[T]: - pass - - def set(self, key: str, val: T, ttl_override: Optional[int] = None) -> None: - pass - - -class CachedItem(Generic[T]): - def __init__(self, value: T, expiration: float): - self.value = value - self.expiration = expiration - - -class LocalCache(CacheProvider[T]): - def __init__(self, max_size: int, ttl: int): - self.cache: OrderedDictType[str, CachedItem[T]] = OrderedDict() - self.max_size = max_size - self.ttl = ttl - - def get(self, key: str) -> Optional[T]: - if self.max_size == 0 or key not in self.cache: - return None - - item = self.cache[key] - current_time = time.time() * 1000 - - if current_time > item.expiration: - del self.cache[key] - return None - - # Move the accessed item to the end (most recently used) - self.cache.move_to_end(key) - return item.value - - def set(self, key: str, val: T, ttl_override: Optional[int] = None) -> None: - if self.max_size == 0: - return - - ttl = self.ttl if ttl_override is None else ttl_override - expiration = time.time() * 1000 + ttl - - # If the key already exists, update it and move it to the end - if key in self.cache: - self.cache[key] = CachedItem(val, expiration) - self.cache.move_to_end(key) - else: - # If we're at capacity, remove the least recently used item - if len(self.cache) >= self.max_size: - self.cache.popitem(last=False) - - # Add the new item - self.cache[key] = CachedItem(val, expiration) - - def clean_expired(self): - current_time = time.time() * 1000 - self.cache = OrderedDict( - (k, v) for k, v in self.cache.items() if v.expiration > current_time - ) diff --git a/src/schematic/cache/__init__.py b/src/schematic/cache/__init__.py new file mode 100644 index 0000000..dc53a89 --- /dev/null +++ b/src/schematic/cache/__init__.py @@ -0,0 +1,26 @@ +from .local import ( + DEFAULT_CACHE_SIZE, + DEFAULT_CACHE_TTL, + DEFAULT_MAX_ITEMS, + DEFAULT_TTL_MS, + AsyncLocalCache, + LocalCache, +) +from .provider import AsyncCacheProvider, CacheProvider +from .redis import RedisCache + +__all__ = [ + # Providers + "AsyncCacheProvider", + "CacheProvider", + # Local cache + "AsyncLocalCache", + "LocalCache", + # Redis cache + "RedisCache", + # Constants + "DEFAULT_CACHE_SIZE", + "DEFAULT_CACHE_TTL", + "DEFAULT_MAX_ITEMS", + "DEFAULT_TTL_MS", +] diff --git a/src/schematic/cache/local.py b/src/schematic/cache/local.py new file mode 100644 index 0000000..f14f8b8 --- /dev/null +++ b/src/schematic/cache/local.py @@ -0,0 +1,146 @@ +from __future__ import annotations + +import time +from collections import OrderedDict +from typing import Any, Generic, List, Optional, Set, TypeVar + +from .provider import AsyncCacheProvider, CacheProvider + +T = TypeVar("T") + +DEFAULT_CACHE_SIZE = 1000 +DEFAULT_CACHE_TTL = 5000 # 5 seconds +DEFAULT_MAX_ITEMS = 1000 +DEFAULT_TTL_MS = 5000 + + +class CachedItem(Generic[T]): + __slots__ = ("value", "expiration") + + def __init__(self, value: T, expiration: float) -> None: + self.value = value + self.expiration = expiration + + +class LocalCache(CacheProvider[T]): + """In-memory synchronous cache with LRU eviction and TTL support.""" + + def __init__(self, max_size: int = DEFAULT_CACHE_SIZE, ttl: int = DEFAULT_CACHE_TTL) -> None: + self.cache: OrderedDict[str, CachedItem[Any]] = OrderedDict() + self.max_size = max_size + self.ttl = ttl + + def get(self, key: str) -> Optional[T]: + if self.max_size == 0 or key not in self.cache: + return None + + item = self.cache[key] + current_time = time.time() * 1000 + + if current_time > item.expiration: + del self.cache[key] + return None + + self.cache.move_to_end(key) + return item.value + + def set(self, key: str, val: T, ttl_override: Optional[int] = None) -> None: + if self.max_size == 0: + return + + ttl = self.ttl if ttl_override is None else ttl_override + expiration = time.time() * 1000 + ttl + + if key in self.cache: + self.cache[key] = CachedItem(val, expiration) + self.cache.move_to_end(key) + else: + if len(self.cache) >= self.max_size: + self.cache.popitem(last=False) + self.cache[key] = CachedItem(val, expiration) + + def clean_expired(self) -> None: + current_time = time.time() * 1000 + self.cache = OrderedDict( + (k, v) for k, v in self.cache.items() if v.expiration > current_time + ) + + +class _AsyncCacheItem(Generic[T]): + __slots__ = ("value", "access_counter", "expiration") + + def __init__(self, value: T, access_counter: int, expiration: float) -> None: + self.value = value + self.access_counter = access_counter + self.expiration = expiration + + +class AsyncLocalCache(AsyncCacheProvider[T]): + """In-memory async cache with LRU eviction and TTL support.""" + + def __init__(self, *, max_items: int = DEFAULT_MAX_ITEMS, ttl: int = DEFAULT_TTL_MS) -> None: + self._cache: OrderedDict[str, _AsyncCacheItem[Any]] = OrderedDict() + self._max_items = max_items + self._default_ttl = ttl + self._access_counter = 0 + + async def get(self, key: str) -> Optional[T]: + item = self._cache.get(key) + if item is None: + return None + + now_ms = time.time() * 1000 + if now_ms >= item.expiration: + del self._cache[key] + return None + + self._access_counter += 1 + item.access_counter = self._access_counter + self._cache.move_to_end(key) + return item.value + + async def set(self, key: str, value: T, ttl: Optional[int] = None) -> None: + if self._max_items == 0: + return + + effective_ttl = ttl if ttl is not None else self._default_ttl + + if key in self._cache: + del self._cache[key] + + self._evict_expired() + + while len(self._cache) >= self._max_items: + oldest_key: Optional[str] = None + oldest_counter = float("inf") + for k, item in self._cache.items(): + if item.access_counter < oldest_counter: + oldest_key = k + oldest_counter = item.access_counter + if oldest_key is not None: + del self._cache[oldest_key] + else: + break + + self._access_counter += 1 + now_ms = time.time() * 1000 + self._cache[key] = _AsyncCacheItem( + value=value, + access_counter=self._access_counter, + expiration=now_ms + effective_ttl, + ) + + async def delete(self, key: str) -> None: + self._cache.pop(key, None) + + async def delete_missing(self, keys_to_keep: List[str], *, scan_pattern: Optional[str] = None) -> None: + keep_set: Set[str] = set(keys_to_keep) + to_delete = [k for k in self._cache if k not in keep_set] + for k in to_delete: + del self._cache[k] + + def _evict_expired(self) -> None: + now_ms = time.time() * 1000 + expired = [k for k, item in self._cache.items() if now_ms >= item.expiration] + for k in expired: + del self._cache[k] diff --git a/src/schematic/cache/provider.py b/src/schematic/cache/provider.py new file mode 100644 index 0000000..1757e93 --- /dev/null +++ b/src/schematic/cache/provider.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +from typing import Generic, List, Optional, TypeVar + +T = TypeVar("T") + + +class CacheProvider(Generic[T]): + """Synchronous cache provider interface.""" + + def get(self, key: str) -> Optional[T]: + pass + + def set(self, key: str, val: T, ttl_override: Optional[int] = None) -> None: + pass + + +class AsyncCacheProvider(Generic[T]): + """Async cache provider interface for storing and retrieving entities.""" + + async def get(self, key: str) -> Optional[T]: + raise NotImplementedError + + async def set(self, key: str, value: T, ttl: Optional[int] = None) -> None: + raise NotImplementedError + + async def delete(self, key: str) -> None: + raise NotImplementedError + + async def delete_missing(self, keys_to_keep: List[str], *, scan_pattern: Optional[str] = None) -> None: + """Delete all keys not in keys_to_keep. Optional for bulk operations.""" + raise NotImplementedError diff --git a/src/schematic/cache/redis.py b/src/schematic/cache/redis.py new file mode 100644 index 0000000..895199e --- /dev/null +++ b/src/schematic/cache/redis.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +import json +import logging +from typing import Any, List, Optional, TypeVar + +from .provider import AsyncCacheProvider + +T = TypeVar("T") + +logger = logging.getLogger(__name__) + +class RedisCache(AsyncCacheProvider[T]): + """Async Redis cache provider using redis.asyncio. + + Stores values as JSON strings. Supports TTL and pattern-based bulk deletion. + + Usage:: + + import redis.asyncio as redis + + pool = redis.ConnectionPool.from_url("redis://localhost:6379") + client = redis.Redis(connection_pool=pool) + cache = RedisCache(client, prefix="schematic:flags") + """ + + def __init__( + self, + client: Any, + *, + prefix: str = "schematic", + default_ttl_ms: Optional[int] = None, + ) -> None: + self._client = client + self._prefix = prefix + self._default_ttl_ms = default_ttl_ms + + def _prefixed(self, key: str) -> str: + return f"{self._prefix}:{key}" + + async def get(self, key: str) -> Optional[T]: + prefixed_key = self._prefixed(key) + raw = await self._client.get(prefixed_key) + logger.debug("Redis GET %s -> %s", prefixed_key, "hit" if raw is not None else "miss") + if raw is None: + return None + try: + return json.loads(raw) + except (json.JSONDecodeError, TypeError): + logger.warning("Failed to deserialize cache value for key: %s", key) + return None + + async def set(self, key: str, value: T, ttl: Optional[int] = None) -> None: + effective_ttl = ttl if ttl is not None else self._default_ttl_ms + serialized = json.dumps(value, default=_json_default) + prefixed = self._prefixed(key) + if effective_ttl is not None: + await self._client.psetex(prefixed, effective_ttl, serialized) + else: + await self._client.set(prefixed, serialized) + + async def delete(self, key: str) -> None: + await self._client.delete(self._prefixed(key)) + + async def delete_missing(self, keys_to_keep: List[str], *, scan_pattern: Optional[str] = None) -> None: + """Delete all keys matching scan_pattern that are not in keys_to_keep. + + Uses SCAN to iterate keys without blocking the server. + """ + pattern = self._prefixed(scan_pattern or "*") + keep_set = {self._prefixed(k) for k in keys_to_keep} + to_delete: list[str] = [] + + async for key in self._client.scan_iter(match=pattern, count=100): + key_str = key.decode("utf-8") if isinstance(key, bytes) else key + if key_str not in keep_set: + to_delete.append(key_str) + + if to_delete: + await self._client.delete(*to_delete) + + +def _json_default(obj: Any) -> Any: + """Default JSON serializer for Pydantic models and datetime objects.""" + if hasattr(obj, "model_dump"): + return obj.model_dump(mode="json") + if hasattr(obj, "dict"): + return obj.dict() + if hasattr(obj, "isoformat"): + return obj.isoformat() + raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable") From 30a0b1e6cea70805685c6799fcfe438eb4d9536e Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 08:39:25 -0600 Subject: [PATCH 03/19] add datastream/replicator functionality --- .claude/skills/pr-review/SKILL.md | 129 +++ .fernignore | 4 +- poetry.lock | 74 +- pyproject.toml | 4 + src/schematic/client.py | 316 ++++- src/schematic/datastream/__init__.py | 24 +- src/schematic/datastream/datastream_client.py | 1031 +++++++++++++++++ src/schematic/datastream/merge.py | 133 +++ src/schematic/datastream/rules_engine.py | 176 +++ src/schematic/datastream/types.py | 21 +- .../datastream/wasm/rulesengine.wasm | Bin 0 -> 615067 bytes src/schematic/datastream/websocket_client.py | 84 +- tests/custom/test_client.py | 140 ++- tests/datastream/__init__.py | 0 tests/datastream/test_cache.py | 93 ++ tests/datastream/test_datastream_client.py | 358 ++++++ tests/datastream/test_merge.py | 542 +++++++++ tests/datastream/test_rules_engine.py | 130 +++ 18 files changed, 3184 insertions(+), 75 deletions(-) create mode 100644 .claude/skills/pr-review/SKILL.md create mode 100644 src/schematic/datastream/datastream_client.py create mode 100644 src/schematic/datastream/merge.py create mode 100644 src/schematic/datastream/rules_engine.py create mode 100755 src/schematic/datastream/wasm/rulesengine.wasm create mode 100644 tests/datastream/__init__.py create mode 100644 tests/datastream/test_cache.py create mode 100644 tests/datastream/test_datastream_client.py create mode 100644 tests/datastream/test_merge.py create mode 100644 tests/datastream/test_rules_engine.py diff --git a/.claude/skills/pr-review/SKILL.md b/.claude/skills/pr-review/SKILL.md new file mode 100644 index 0000000..42a0add --- /dev/null +++ b/.claude/skills/pr-review/SKILL.md @@ -0,0 +1,129 @@ +--- +name: pr-review +description: Review code changes on the current branch for quality, bugs, performance, and security +disable-model-invocation: true +argument-hint: "[optional: LINEAR-TICKET-ID]" +allowed-tools: Read, Grep, Glob, Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git branch:*), Bash(gh pr:*), Bash(gh api:*), Bash(~/.claude/scripts/fetch-github-pr.sh:*), Bash(~/.claude/scripts/fetch-sentry-data.sh:*), Bash(~/.claude/scripts/fetch-slack-thread.sh:*) +--- + +# Code Review + +You are reviewing code changes on the current branch. Your review must be based on the **current state of the code right now**, not on anything you've seen earlier in this conversation. + +## CRITICAL: Always Use Fresh Data + +**IGNORE any file contents, diffs, or line numbers you may have seen earlier in this conversation.** They may be stale. You MUST re-fetch everything from scratch using the commands below. + +## Step 1: Get the Current Diff and PR Context + +Run ALL of these commands to get a fresh view: + +```bash +# The authoritative diff -- only review what's in HERE +git diff main...HEAD + +# Recent commits on this branch +git log --oneline main..HEAD + +# PR description and comments +gh pr view --json number,title,body,comments,reviews,reviewRequests +``` + +Also fetch PR review comments (inline code comments): + +```bash +# Get the PR number +PR_NUMBER=$(gh pr view --json number -q '.number') + +# Fetch all review comments (inline comments on specific lines) +gh api repos/{owner}/{repo}/pulls/$PR_NUMBER/comments --jq '.[] | {path: .path, line: .line, body: .body, user: .user.login, created_at: .created_at}' + +# Fetch review-level comments (general review comments) +gh api repos/{owner}/{repo}/pulls/$PR_NUMBER/reviews --jq '.[] | {state: .state, body: .body, user: .user.login}' +``` + +## Step 2: Understand Context from PR Comments + +Before reviewing, read through the PR comments and review comments. Note **who** said what (by username). + +- **Already-addressed feedback**: If a reviewer pointed out an issue and the author has already fixed it (the fix is visible in the current diff), do NOT re-raise it. +- **Ongoing discussions**: Note any unresolved threads -- your review should take these into account. +- **Previous approvals/requests for changes**: Understand what reviewers have already looked at. + +**IMPORTANT**: Your review is YOUR independent review. Do not take credit for or reference other reviewers' findings as if they were yours. If another reviewer already flagged something, you can note "as [reviewer] pointed out" but do not present their feedback as your own prior review. Your verdict should be based solely on your own analysis of the current code. + +## Step 3: Get Requirements Context + +Check if a Linear ticket ID was provided as an argument ($ARGUMENTS). If not, try to extract it from the branch name (pattern: `{username}/{linear-ticket}-{title}`). + +If a Linear ticket is found: +- Use Linear MCP tools (`get_issue`) to get the issue details and comments +- **Check for a parent ticket**: If the issue has a parent issue, fetch the parent too. Our pattern is to have a parent ticket with project-wide requirements and sub-tickets for specific tasks (often one per repo/PR). The parent ticket will contain the full scope of the project, while the sub-ticket scopes what this specific PR should cover. Use both to assess completeness — the PR should fulfill the sub-ticket's scope, and that scope should be a reasonable subset of the parent's backend-related requirements. +- Look for Sentry links in the description/comments; if found, use Sentry MCP tools to get error details +- Assess whether the changes fulfill the ticket requirements + +If no ticket is found, check the PR description for context on what the changes are meant to accomplish. + +## Step 4: Review the Code + +Review ONLY the changed lines (from `git diff main...HEAD`). Do not comment on unchanged code. + +**When referencing code, always use the file path and quote the actual code snippet** rather than citing line numbers, since line numbers shift as the branch evolves. + +### Code Quality +- Is the code well-structured and maintainable? +- Does it follow CLAUDE.md conventions? (import grouping, error handling with lib/errors, naming, alphabetization, etc.) +- Any AI-generated slop? (excessive comments, unnecessary abstractions, over-engineering) + +### Performance +- N+1 queries, inefficient loops, missing indexes for new queries +- Unbuffered writes in hot paths (especially ClickHouse) +- Missing LIMIT clauses on potentially large result sets + +### Bugs +- Nil pointer risks (especially on struct pointer params and optional relations) +- Functions returning `nil, nil` (violates convention) +- Missing error handling +- Race conditions in concurrent code paths + +### Security +- Hardcoded secrets or sensitive data exposure +- Missing input validation on service request structs + +### Tests +- Are there tests for the new/changed code? +- Do the tests cover edge cases and error paths? +- Are test assertions specific (not just "no error")? + +## Step 5: Present the Review + +Structure your review as: + +``` +## Summary +[1-2 sentences: what this PR does and overall assessment] + +## Requirements Check +[Does the PR fulfill the Linear ticket / PR description requirements? Any gaps?] + +## Issues +### Critical (must fix before merge) +- [blocking issues] + +### Suggestions (nice to have) +- [non-blocking improvements] + +## Prior Review Activity +[Summarize what other reviewers have flagged, attributed by name. Note which of their concerns have been addressed in the current code and which remain open.] + +## Verdict +[LGTM / Needs changes / Needs discussion -- based on YOUR analysis, not other reviewers' findings] +``` + +## Guidelines + +- Be concise. Don't pad with praise or filler. +- Only raise issues that matter. Don't nitpick formatting (that's what linters are for). +- Quote code snippets rather than referencing line numbers. +- If PR comments show a discussion was already resolved, don't reopen it. +- If you're unsure about something, flag it as a question rather than a definitive issue. diff --git a/.fernignore b/.fernignore index e79778f..c60cef2 100644 --- a/.fernignore +++ b/.fernignore @@ -7,9 +7,10 @@ README.md src/schematic/client.py # Additional custom code +.claude/ .github/CODEOWNERS scripts/ -src/schematic/cache.py +src/schematic/cache/ src/schematic/event_buffer.py src/schematic/http_client.py src/schematic/logging.py @@ -17,5 +18,6 @@ src/schematic/datastream/ src/schematic/webhook_utils/ src/schematic/webhooks/verification.py tests/custom/ +tests/datastream/ tests/webhook_utils/ CLAUDE.md diff --git a/poetry.lock b/poetry.lock index bea4166..ec1590f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -171,6 +171,30 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "importlib-resources" +version = "6.4.5" +description = "Read resources from Python packages" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"rulesengine\"" +files = [ + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + [[package]] name = "iniconfig" version = "2.1.0" @@ -623,6 +647,30 @@ files = [ {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] +[[package]] +name = "wasmtime" +version = "25.0.0" +description = "A WebAssembly runtime powered by Wasmtime" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"rulesengine\"" +files = [ + {file = "wasmtime-25.0.0-py3-none-any.whl", hash = "sha256:22aa59fc6e01deec8a6703046f82466090d5811096a3bb5c169907e36c842af1"}, + {file = "wasmtime-25.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:13e9a718e9d580c1738782cc19f4dcb9fb068f7e51778ea621fd664f4433525b"}, + {file = "wasmtime-25.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5bdf1214ee3ee78a4a8a92da339f4c4c8c109e65af881b37f4adfc05d02af426"}, + {file = "wasmtime-25.0.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:b4364e14d44e3b7afe6a40bf608e9d0d2c40b09dece441d20f4f6e31906b729c"}, + {file = "wasmtime-25.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a07445073cf36a6e5d1dc28246a897dcbdaa537ba8be8805be65422ecca297eb"}, + {file = "wasmtime-25.0.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:53d5f614348a28aabdf80ae4f6fdfa803031af1f74ada03826fd4fd43aeee6c8"}, + {file = "wasmtime-25.0.0-py3-none-win_amd64.whl", hash = "sha256:f8a2a213b9179965db2d2eedececd69a37e287e902330509afae51c71a3a6842"}, +] + +[package.dependencies] +importlib-resources = ">=5.10" + +[package.extras] +testing = ["componentize-py", "coverage", "pycparser", "pytest", "pytest-mypy"] + [[package]] name = "websockets" version = "13.1" @@ -719,7 +767,31 @@ files = [ {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, ] +[[package]] +name = "zipp" +version = "3.20.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"rulesengine\" and python_version < \"3.10\"" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[extras] +rulesengine = ["wasmtime"] + [metadata] lock-version = "2.1" python-versions = "^3.8" -content-hash = "4938beb3198ee4d1c0088267e91cd608c926c85825b39afdd9ab5b160a2a8df1" +content-hash = "fac28b41db959c73343ddaccefd13515de5f557e0eb8de7b2fa0f84ca98e96f6" diff --git a/pyproject.toml b/pyproject.toml index 63a5cec..1850ea4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,10 @@ pydantic = ">= 1.9.2" pydantic-core = ">=2.18.2" typing_extensions = ">= 4.0.0" websockets = ">=10.0" +wasmtime = { version = ">=19.0.0", optional = true } + +[tool.poetry.extras] +rulesengine = ["wasmtime"] [tool.poetry.group.dev.dependencies] mypy = "==1.13.0" diff --git a/src/schematic/client.py b/src/schematic/client.py index 1a649b5..5b09c95 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -1,24 +1,51 @@ import atexit import logging from dataclasses import dataclass -from typing import Any, Dict, List, Optional +from typing import Any, Callable, Dict, List, Optional, Union import httpx from .base_client import AsyncBaseSchematic, BaseSchematic -from .cache import DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL, CacheProvider, LocalCache +from .cache import DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL, AsyncCacheProvider, CacheProvider, LocalCache +from .datastream import DataStreamClient, DataStreamClientOptions from .event_buffer import AsyncEventBuffer, EventBuffer from .http_client import AsyncOfflineHTTPClient, OfflineHTTPClient from .logging import get_default_logger from .types import ( + CheckFlagRequestBody, + CheckFlagResponseData, CreateEventRequestBody, EventBody, + EventBodyFlagCheck, EventBodyIdentify, EventBodyIdentifyCompany, EventBodyTrack, ) +@dataclass +class CheckFlagOptions: + """Options for flag check methods.""" + + default_value: Optional[Union[bool, Callable[[], bool]]] = None + timeout: Optional[float] = None + + +@dataclass +class DataStreamConfig: + """Configuration for DataStream real-time flag evaluation.""" + + cache_ttl: Optional[int] = None + company_cache: Optional[AsyncCacheProvider[Any]] = None + company_lookup_cache: Optional[AsyncCacheProvider[str]] = None + user_cache: Optional[AsyncCacheProvider[Any]] = None + user_lookup_cache: Optional[AsyncCacheProvider[str]] = None + flag_cache: Optional[AsyncCacheProvider[Any]] = None + replicator_mode: bool = False + replicator_health_url: Optional[str] = None + replicator_health_check: Optional[int] = None + + @dataclass class SchematicConfig: base_url: Optional[str] = None @@ -29,7 +56,7 @@ class SchematicConfig: logger: Optional[logging.Logger] = None offline: bool = False timeout: Optional[float] = None - cache_providers: Optional[List[CacheProvider[bool]]] = None + cache_providers: Optional[List[CacheProvider[CheckFlagResponseData]]] = None class Schematic(BaseSchematic): @@ -52,8 +79,8 @@ def __init__(self, api_key: str, config: Optional[SchematicConfig] = None): logger=self.logger, period=self.event_buffer_period, ) - self.flag_check_cache_providers = config.cache_providers or [ - LocalCache[bool](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) + self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = config.cache_providers or [ + LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) ] self.offline = config.offline @@ -70,16 +97,38 @@ def check_flag( flag_key: str, company: Optional[Dict[str, str]] = None, user: Optional[Dict[str, str]] = None, + options: Optional[CheckFlagOptions] = None, ) -> bool: + resp = self.check_flag_with_entitlement(flag_key, company=company, user=user, options=options) + return resp.value + + def check_flag_with_entitlement( + self, + flag_key: str, + company: Optional[Dict[str, str]] = None, + user: Optional[Dict[str, str]] = None, + options: Optional[CheckFlagOptions] = None, + ) -> CheckFlagResponseData: + default_value = self._resolve_default(flag_key, options) + if self.offline: - return self._get_flag_default(flag_key) + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) + return self._check_flag_via_api(flag_key, company, user, default_value) + + def _check_flag_via_api( + self, + flag_key: str, + company: Optional[Dict[str, str]], + user: Optional[Dict[str, str]], + default_value: bool, + ) -> CheckFlagResponseData: try: - cache_key = ( - flag_key + ":" + str(company) + ":" + str(user) - if (company or user) - else flag_key - ) + cache_key = _build_cache_key(flag_key, company, user) for provider in self.flag_check_cache_providers: cached_value = provider.get(cache_key) @@ -87,16 +136,26 @@ def check_flag( return cached_value resp = self.features.check_flag(flag_key, company=company, user=user) - if resp is None: - return self._get_flag_default(flag_key) + if resp is None or resp.data.value is None: + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) + + result = _api_response_to_result(resp.data) for provider in self.flag_check_cache_providers: - provider.set(cache_key, resp.data.value) + provider.set(cache_key, result) - return resp.data.value + return result except Exception as e: self.logger.error(e) - return self._get_flag_default(flag_key) + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) def identify( self, @@ -146,6 +205,13 @@ def _enqueue_event(self, event_type: str, body: EventBody) -> None: def _get_flag_default(self, flag_key: str) -> bool: return self.flag_defaults.get(flag_key, False) + def _resolve_default(self, flag_key: str, options: Optional[CheckFlagOptions] = None) -> bool: + if options and options.default_value is not None: + if callable(options.default_value): + return options.default_value() + return options.default_value + return self._get_flag_default(flag_key) + @dataclass class AsyncSchematicConfig: @@ -157,36 +223,38 @@ class AsyncSchematicConfig: logger: Optional[logging.Logger] = None offline: bool = False timeout: Optional[float] = None - cache_providers: Optional[List[CacheProvider[bool]]] = None + cache_providers: Optional[List[CacheProvider[CheckFlagResponseData]]] = None + use_datastream: bool = False + datastream: Optional[DataStreamConfig] = None class AsyncSchematic(AsyncBaseSchematic): """Async Schematic client for feature flags and event tracking. - + This client provides async methods for checking feature flags and tracking events. - It automatically initializes on first use and maintains background tasks for + It automatically initializes on first use and maintains background tasks for event buffering that require proper cleanup. - + IMPORTANT: Always call shutdown() when done, or use as a context manager: - + # Recommended patterns: - + # 1. Context manager (automatic cleanup): async with AsyncSchematic(api_key, config) as client: result = await client.check_flag("my-flag") # Auto-initializes - + # 2. Manual (explicit cleanup): client = AsyncSchematic(api_key, config) try: result = await client.check_flag("my-flag") # Auto-initializes finally: await client.shutdown() # REQUIRED for proper cleanup - + # 3. Web framework (lifecycle managed): # In startup: client = AsyncSchematic(api_key, config) # In shutdown: await client.shutdown() """ - + def __init__(self, api_key: str, config: Optional[AsyncSchematicConfig] = None): self._initialized = False config = config or AsyncSchematicConfig() @@ -209,38 +277,142 @@ def __init__(self, api_key: str, config: Optional[AsyncSchematicConfig] = None): logger=self.logger, period=self.event_buffer_period, ) - self.flag_check_cache_providers = config.cache_providers or [ - LocalCache[bool](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) + self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = config.cache_providers or [ + LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) ] self.offline = config.offline self._shutdown_requested = False self._is_shutting_down = False + + # DataStream client + self._datastream_client: Optional[DataStreamClient] = None + if config.use_datastream and not config.offline: + ds = config.datastream or DataStreamConfig() + ds_opts = DataStreamClientOptions( + api_key=api_key, + base_url=config.base_url, + logger=self.logger, + ) + if ds.cache_ttl is not None: + ds_opts.cache_ttl = ds.cache_ttl + if ds.company_cache is not None: + ds_opts.company_cache = ds.company_cache + if ds.company_lookup_cache is not None: + ds_opts.company_lookup_cache = ds.company_lookup_cache + if ds.user_cache is not None: + ds_opts.user_cache = ds.user_cache + if ds.user_lookup_cache is not None: + ds_opts.user_lookup_cache = ds.user_lookup_cache + if ds.flag_cache is not None: + ds_opts.flag_cache = ds.flag_cache + ds_opts.replicator_mode = ds.replicator_mode + if ds.replicator_health_url is not None: + ds_opts.replicator_health_url = ds.replicator_health_url + if ds.replicator_health_check is not None: + ds_opts.replicator_health_check = ds.replicator_health_check + + self._datastream_client = DataStreamClient(ds_opts) + self._initialized = True async def __aenter__(self): + await self._start_datastream() return self async def __aexit__(self, exc_type, exc_val, exc_tb): await self.shutdown() + async def _start_datastream(self) -> None: + if self._datastream_client is not None: + try: + await self._datastream_client.start() + except Exception as e: + self.logger.error(f"Failed to start DataStream client: {e}") + self._datastream_client = None + async def initialize(self) -> None: - pass + await self._start_datastream() + + def _get_datastream(self) -> Optional[DataStreamClient]: + return self._datastream_client async def check_flag( self, flag_key: str, company: Optional[Dict[str, str]] = None, user: Optional[Dict[str, str]] = None, + options: Optional[CheckFlagOptions] = None, ) -> bool: + resp = await self.check_flag_with_entitlement(flag_key, company=company, user=user, options=options) + return resp.value + + async def check_flag_with_entitlement( + self, + flag_key: str, + company: Optional[Dict[str, str]] = None, + user: Optional[Dict[str, str]] = None, + options: Optional[CheckFlagOptions] = None, + ) -> CheckFlagResponseData: + default_value = self._resolve_default(flag_key, options) + if self.offline: - return self._get_flag_default(flag_key) + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) + # Try DataStream first if available + ds = self._get_datastream() + if ds is not None: + try: + resp = await ds.check_flag( + CheckFlagRequestBody(company=company, user=user), + flag_key, + ) + + # Enqueue flag_check event + await self._enqueue_event( + "flag_check", + EventBodyFlagCheck( + flag_key=flag_key, + value=resp.value if resp.value is not None else False, + reason=resp.reason if resp.reason else "unknown", + rule_id=getattr(resp, "rule_id", None), + company_id=getattr(resp, "company_id", None), + user_id=getattr(resp, "user_id", None), + flag_id=getattr(resp, "flag_id", None), + req_company=company, + req_user=user, + ), + ) + + return CheckFlagResponseData( + company_id=getattr(resp, "company_id", None), + entitlement=getattr(resp, "entitlement", None), + error=getattr(resp, "err", None), + flag=getattr(resp, "flag", flag_key), + flag_id=getattr(resp, "flag_id", None), + reason=resp.reason, + rule_id=getattr(resp, "rule_id", None), + rule_type=getattr(resp, "rule_type", None), + user_id=getattr(resp, "user_id", None), + value=resp.value if resp.value is not None else self._get_flag_default(flag_key), + ) + except Exception as e: + self.logger.debug(f"Datastream flag check failed ({e}), falling back to API") + + return await self._check_flag_via_api(flag_key, company, user, default_value) + + async def _check_flag_via_api( + self, + flag_key: str, + company: Optional[Dict[str, str]], + user: Optional[Dict[str, str]], + default_value: bool, + ) -> CheckFlagResponseData: try: - cache_key = ( - flag_key + ":" + str(company) + ":" + str(user) - if (company or user) - else flag_key - ) + cache_key = _build_cache_key(flag_key, company, user) for provider in self.flag_check_cache_providers: cached_value = provider.get(cache_key) @@ -248,16 +420,26 @@ async def check_flag( return cached_value resp = await self.features.check_flag(flag_key, company=company, user=user) - if resp is None: - return self._get_flag_default(flag_key) + if resp is None or resp.data.value is None: + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) + + result = _api_response_to_result(resp.data) for provider in self.flag_check_cache_providers: - provider.set(cache_key, resp.data.value) + provider.set(cache_key, result) - return resp.data.value + return result except Exception as e: self.logger.error(e) - return self._get_flag_default(flag_key) + return CheckFlagResponseData( + flag=flag_key, + reason="flag default", + value=default_value, + ) async def identify( self, @@ -265,7 +447,7 @@ async def identify( company: Optional[EventBodyIdentifyCompany] = None, name: Optional[str] = None, traits: Optional[Dict[str, Any]] = None, - ) -> None: + ) -> None: await self._enqueue_event( "identify", EventBodyIdentify( @@ -283,7 +465,7 @@ async def track( user: Optional[Dict[str, str]] = None, traits: Optional[Dict[str, Any]] = None, quantity: Optional[int] = None, - ) -> None: + ) -> None: await self._enqueue_event( "track", EventBodyTrack( @@ -295,6 +477,18 @@ async def track( ), ) + # Update company metrics in DataStream if available and connected + ds = self._get_datastream() + if company and ds is not None and ds.is_connected(): + try: + await ds.update_company_metrics( + company, + event, + quantity or 1, + ) + except Exception as e: + self.logger.error(f"Failed to update company metrics: {e}") + async def _enqueue_event(self, event_type: str, body: EventBody) -> None: if self.offline: return @@ -307,31 +501,44 @@ async def _enqueue_event(self, event_type: str, body: EventBody) -> None: def _get_flag_default(self, flag_key: str) -> bool: return self.flag_defaults.get(flag_key, False) + def _resolve_default(self, flag_key: str, options: Optional[CheckFlagOptions] = None) -> bool: + if options and options.default_value is not None: + if callable(options.default_value): + return options.default_value() + return options.default_value + return self._get_flag_default(flag_key) + async def shutdown(self) -> None: """Properly shutdown the client, flushing any pending events. - + This method should be called when you're done using the client to ensure: - All pending events are flushed to the server - Background tasks are properly terminated - Resources are cleaned up - + It's safe to call this method multiple times, even if the client was never used. """ # Only do the shutdown once if self._is_shutting_down: self.logger.debug("Shutdown already in progress, skipping") return - + self._is_shutting_down = True - + # If we were never initialized, there's nothing to clean up if not self._initialized: self.logger.debug("Client was never initialized, nothing to clean up") return - + self.logger.info("Shutting down AsyncSchematic...") - + try: + if self._datastream_client is not None: + try: + await self._datastream_client.close_async() + except Exception as e: + self.logger.error(f"Error closing DataStream client: {e}") + # Flush and stop the event buffer await self.event_buffer.stop() self.logger.info("Shutdown complete.") @@ -339,4 +546,17 @@ async def shutdown(self) -> None: self.logger.error(f"Error during shutdown: {e}") finally: self._shutdown_requested = True - + + +def _build_cache_key( + flag_key: str, + company: Optional[Dict[str, str]] = None, + user: Optional[Dict[str, str]] = None, +) -> str: + if company or user: + return flag_key + ":" + str(company) + ":" + str(user) + return flag_key + + +def _api_response_to_result(data: CheckFlagResponseData) -> CheckFlagResponseData: + return data diff --git a/src/schematic/datastream/__init__.py b/src/schematic/datastream/__init__.py index b777f85..7ed02c5 100644 --- a/src/schematic/datastream/__init__.py +++ b/src/schematic/datastream/__init__.py @@ -1,14 +1,34 @@ +from ..cache import AsyncCacheProvider, AsyncLocalCache +from .datastream_client import DataStreamClient, DataStreamClientOptions +from .merge import deep_copy_company, deep_copy_user, extract_id, partial_company, partial_user +from .rules_engine import RulesEngineClient from .types import DataStreamBaseReq, DataStreamError, DataStreamReq, DataStreamResp, EntityType, MessageType from .websocket_client import ClientOptions, DatastreamWSClient, convert_api_url_to_websocket_url __all__ = [ - "ClientOptions", + # Cache + "AsyncCacheProvider", + "AsyncLocalCache", + # Datastream client + "DataStreamClient", + "DataStreamClientOptions", + # Merge utilities + "deep_copy_company", + "deep_copy_user", + "extract_id", + "partial_company", + "partial_user", + # Rules engine + "RulesEngineClient", + # Types "DataStreamBaseReq", "DataStreamError", "DataStreamReq", "DataStreamResp", - "DatastreamWSClient", "EntityType", "MessageType", + # WebSocket client + "ClientOptions", + "DatastreamWSClient", "convert_api_url_to_websocket_url", ] diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py new file mode 100644 index 0000000..b4307aa --- /dev/null +++ b/src/schematic/datastream/datastream_client.py @@ -0,0 +1,1031 @@ +from __future__ import annotations + +import asyncio +import json +import logging +from dataclasses import dataclass, field +from typing import Any, Callable, Dict, List, Optional, Set, Union + +from ..types.check_flag_request_body import CheckFlagRequestBody +from ..types.rulesengine_check_flag_result import RulesengineCheckFlagResult +from ..types.rulesengine_company import RulesengineCompany +from ..types.rulesengine_flag import RulesengineFlag +from ..types.rulesengine_user import RulesengineUser +from ..cache import AsyncCacheProvider, AsyncLocalCache +from .merge import partial_company, partial_user +from .rules_engine import RulesEngineClient +from .types import DataStreamBaseReq, DataStreamReq, DataStreamResp, EntityType, MessageType +from .websocket_client import ClientOptions as WSClientOptions, DatastreamWSClient + + +def _coerce_nulls(data: dict, model_cls: type) -> dict: + """Convert null values to empty lists for required list fields. + + Go serializes nil slices as JSON null, but our Pydantic models require + lists. This recursively fixes nulls before model_validate. + """ + import typing + if not hasattr(model_cls, "__annotations__"): + return data + + hints = typing.get_type_hints(model_cls) + result = dict(data) + for field_name, field_type in hints.items(): + if field_name not in result: + continue + origin = getattr(field_type, "__origin__", None) + args = getattr(field_type, "__args__", ()) + + # typing.List[X] — coerce None to [] + if origin is list and result[field_name] is None: + result[field_name] = [] + # typing.List[Model] — recurse into each element + elif origin is list and args and isinstance(result[field_name], list): + inner = args[0] + if hasattr(inner, "__annotations__"): + result[field_name] = [ + _coerce_nulls(item, inner) if isinstance(item, dict) else item + for item in result[field_name] + ] + return result + + +def _validate(model_cls: type, raw: Any) -> Any: + """Validate raw data into a Pydantic model, coercing Go-style nulls first.""" + if isinstance(raw, dict): + return model_cls.model_validate(_coerce_nulls(raw, model_cls)) + return raw + + +# Cache key prefixes +_PREFIX_COMPANY = "company" +_PREFIX_USER = "user" +_PREFIX_FLAGS = "flags" + +# Timing constants (milliseconds) +RESOURCE_TIMEOUT_MS = 30_000 # 30 seconds +DEFAULT_TTL_MS = 24 * 60 * 60 * 1000 # 24 hours +MAX_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000 # 30 days +DEFAULT_REPLICATOR_HEALTH_CHECK_MS = 30_000 # 30 seconds +REPLICATOR_HEALTH_TIMEOUT_S = 5.0 +REPLICATOR_CACHE_VERSION_TIMEOUT_S = 2.0 + + +@dataclass +class DataStreamClientOptions: + """Configuration for the DataStream client.""" + + api_key: str + logger: logging.Logger + base_url: Optional[str] = None + cache_ttl: int = DEFAULT_TTL_MS + + # Custom cache providers (override defaults) + company_cache: Optional[AsyncCacheProvider[Any]] = None + company_lookup_cache: Optional[AsyncCacheProvider[str]] = None + user_cache: Optional[AsyncCacheProvider[Any]] = None + user_lookup_cache: Optional[AsyncCacheProvider[str]] = None + flag_cache: Optional[AsyncCacheProvider[Any]] = None + + # Replicator mode + replicator_mode: bool = False + replicator_health_url: Optional[str] = None + replicator_health_check: int = DEFAULT_REPLICATOR_HEALTH_CHECK_MS + + # Event callbacks + on_connected: Optional[Callable[[], None]] = None + on_disconnected: Optional[Callable[[], None]] = None + on_ready: Optional[Callable[[], None]] = None + on_not_ready: Optional[Callable[[], None]] = None + on_error: Optional[Callable[[Exception], None]] = None + on_replicator_health_changed: Optional[Callable[[bool], None]] = None + + +class DataStreamClient: + """Datastream client with caching, WASM flag evaluation, and replicator support. + + Manages a WebSocket connection to Schematic's datastream, caches entities + locally, and evaluates feature flags using the WASM rules engine. + + In **replicator mode** no WebSocket connection is established — the client + relies entirely on a shared cache populated by an external replicator + service and performs health checks against a configurable URL. + + Usage:: + + client = DataStreamClient(DataStreamClientOptions( + api_key="your-api-key", + base_url="https://api.schematichq.com", + logger=logging.getLogger(__name__), + )) + await client.start() + result = await client.check_flag(CheckFlagRequestBody(company={"id": "co_123"}), "premium-feature") + client.close() + """ + + def __init__(self, options: DataStreamClientOptions) -> None: + self._api_key = options.api_key + self._base_url = options.base_url + self._logger = options.logger + self._cache_ttl = options.cache_ttl + + # Callbacks + self._on_connected = options.on_connected + self._on_disconnected = options.on_disconnected + self._on_ready = options.on_ready + self._on_not_ready = options.on_not_ready + self._on_error = options.on_error + self._on_replicator_health_changed = options.on_replicator_health_changed + + # Replicator mode + self._replicator_mode = options.replicator_mode + self._replicator_health_url = options.replicator_health_url + self._replicator_health_check_ms = options.replicator_health_check + self._replicator_ready = False + self._replicator_health_task: Optional[asyncio.Task[None]] = None + self._replicator_cache_version: Optional[str] = None + + if self._replicator_mode: + caches = [ + options.company_cache, options.company_lookup_cache, + options.user_cache, options.user_lookup_cache, + options.flag_cache, + ] + if not all(caches): + raise ValueError( + "Replicator mode requires custom cache providers for company, company_lookup, " + "user, user_lookup, and flag caches" + ) + for c in caches: + if isinstance(c, AsyncLocalCache): + raise TypeError( + "Replicator mode requires shared cache providers (e.g. RedisCache), " + "not AsyncLocalCache, to ensure shared state across processes" + ) + + # Cache providers + flag_ttl = max(MAX_CACHE_TTL_MS, self._cache_ttl) + self._company_cache: AsyncCacheProvider[RulesengineCompany] = options.company_cache or AsyncLocalCache(ttl=self._cache_ttl) + self._user_cache: AsyncCacheProvider[RulesengineUser] = options.user_cache or AsyncLocalCache(ttl=self._cache_ttl) + self._flag_cache: AsyncCacheProvider[RulesengineFlag] = options.flag_cache or AsyncLocalCache(ttl=flag_ttl) + + # Key -> ID mapping caches (two-level caching) + self._company_key_cache: AsyncCacheProvider[str] = options.company_lookup_cache or AsyncLocalCache(ttl=self._cache_ttl) + self._user_key_cache: AsyncCacheProvider[str] = options.user_lookup_cache or AsyncLocalCache(ttl=self._cache_ttl) + + # WebSocket client + self._ws_client: Optional[DatastreamWSClient] = None + + # Rules engine + self._rules_engine = RulesEngineClient() + + # Pending requests — maps cache key to list of asyncio Futures + self._pending_company: Dict[str, List[asyncio.Future[RulesengineCompany]]] = {} + self._pending_user: Dict[str, List[asyncio.Future[RulesengineUser]]] = {} + self._pending_flags: Optional[asyncio.Future[bool]] = None + + # ------------------------------------------------------------------ + # Public API + # ------------------------------------------------------------------ + + async def start(self) -> None: + """Initialise and start the datastream client.""" + # Initialise the rules engine + try: + await self._rules_engine.initialize() + self._logger.debug("Rules engine initialized successfully") + except Exception as exc: + self._logger.warning("Failed to initialize rules engine: %s", exc) + + # Replicator mode — no WebSocket + if self._replicator_mode: + self._logger.info("Replicator mode enabled — skipping WebSocket connection") + if self._replicator_health_url: + # Run an initial health check synchronously so the cache version + # is available before the first flag check arrives. + await self._check_replicator_health() + self._start_replicator_health_check() + return + + if not self._base_url: + raise ValueError("base_url is required when not in replicator mode") + + self._logger.info("Starting DataStream client") + + self._ws_client = DatastreamWSClient(WSClientOptions( + url=self._base_url, + api_key=self._api_key, + message_handler=self._handle_message, + logger=self._logger, + connection_ready_handler=self._handle_connection_ready, + on_connected=self._on_ws_connected, + on_disconnected=self._on_ws_disconnected, + on_ready=self._on_ready, + on_not_ready=self._on_not_ready, + on_error=self._on_ws_error, + )) + self._ws_client.start() + + def is_connected(self) -> bool: + if self._replicator_mode: + return self._replicator_ready + return self._ws_client.is_connected() if self._ws_client else False + + def is_replicator_ready(self) -> bool: + return self._replicator_ready + + def is_replicator_mode(self) -> bool: + return self._replicator_mode + + @property + def replicator_cache_version(self) -> Optional[str]: + return self._replicator_cache_version + + async def get_company(self, keys: Dict[str, str]) -> RulesengineCompany: + """Retrieve a company by keys, using cache or datastream.""" + cached = await self._get_company_from_cache(keys) + if cached is not None: + self._logger.debug("Company found in cache for keys: %s", keys) + return cached + + if self._replicator_mode: + raise RuntimeError("Company not found in cache and replicator mode is enabled") + + if not self.is_connected(): + raise RuntimeError("DataStream client is not connected") + + cache_keys = self._generate_company_cache_keys(keys) + existing = any(k in self._pending_company for k in cache_keys) + + loop = asyncio.get_running_loop() + future: asyncio.Future[Any] = loop.create_future() + + for ck in cache_keys: + self._pending_company.setdefault(ck, []).append(future) + + if not existing: + try: + await self._send_request(DataStreamReq(entity_type=EntityType.COMPANY, keys=keys)) + except Exception as exc: + self._cleanup_pending_company(cache_keys, future) + raise + + try: + return await asyncio.wait_for(asyncio.shield(future), timeout=RESOURCE_TIMEOUT_MS / 1000) + except asyncio.TimeoutError: + self._cleanup_pending_company(cache_keys, future) + raise TimeoutError("Timeout while waiting for company data") + + async def get_user(self, keys: Dict[str, str]) -> RulesengineUser: + """Retrieve a user by keys, using cache or datastream.""" + cached = await self._get_user_from_cache(keys) + if cached is not None: + self._logger.debug("User found in cache for keys: %s", keys) + return cached + + if self._replicator_mode: + raise RuntimeError("User not found in cache and replicator mode is enabled") + + if not self.is_connected(): + raise RuntimeError("DataStream client is not connected") + + cache_keys = self._generate_user_cache_keys(keys) + existing = any(k in self._pending_user for k in cache_keys) + + loop = asyncio.get_running_loop() + future: asyncio.Future[Any] = loop.create_future() + + for ck in cache_keys: + self._pending_user.setdefault(ck, []).append(future) + + if not existing: + try: + await self._send_request(DataStreamReq(entity_type=EntityType.USER, keys=keys)) + except Exception as exc: + self._cleanup_pending_user(cache_keys, future) + raise + + try: + return await asyncio.wait_for(asyncio.shield(future), timeout=RESOURCE_TIMEOUT_MS / 1000) + except asyncio.TimeoutError: + self._cleanup_pending_user(cache_keys, future) + raise TimeoutError("Timeout while waiting for user data") + + async def get_flag(self, flag_key: str) -> Optional[RulesengineFlag]: + """Retrieve a flag by key from cache.""" + cache_key = self._flag_cache_key(flag_key) + self._logger.debug("Looking up flag cache key: %s (version=%s)", cache_key, self._get_version_key()) + try: + raw = await self._flag_cache.get(cache_key) + if raw is None: + self._logger.debug("Flag cache miss for key: %s", cache_key) + return None + return _validate(RulesengineFlag, raw) + except Exception as exc: + self._logger.warning("Failed to retrieve flag from cache: %s", exc) + return None + + async def get_all_flags(self) -> None: + """Request a refresh of all flags from the datastream.""" + if self._pending_flags is not None and not self._pending_flags.done(): + # Wait for existing request + await asyncio.wait_for(asyncio.shield(self._pending_flags), timeout=RESOURCE_TIMEOUT_MS / 1000) + return + + loop = asyncio.get_running_loop() + self._pending_flags = loop.create_future() + + try: + await self._send_request(DataStreamReq(entity_type=EntityType.FLAGS)) + except Exception: + fut = self._pending_flags + self._pending_flags = None + if not fut.done(): + fut.set_result(False) + raise + + try: + await asyncio.wait_for(asyncio.shield(self._pending_flags), timeout=RESOURCE_TIMEOUT_MS / 1000) + except asyncio.TimeoutError: + self._pending_flags = None + raise TimeoutError("Timeout while waiting for flags data") + + async def check_flag( + self, + eval_ctx: CheckFlagRequestBody, + flag_key: str, + ) -> RulesengineCheckFlagResult: + """Evaluate a flag for a company and/or user context.""" + flag = await self.get_flag(flag_key) + if flag is None: + raise RuntimeError(f"Flag not found: {flag_key}") + + company_keys = eval_ctx.company + user_keys = eval_ctx.user + needs_company = bool(company_keys) + needs_user = bool(user_keys) + + cached_company: Optional[Any] = None + cached_user: Optional[Any] = None + + if needs_company: + cached_company = await self._get_company_from_cache(company_keys) # type: ignore[arg-type] + if needs_user: + cached_user = await self._get_user_from_cache(user_keys) # type: ignore[arg-type] + + # Replicator mode — evaluate with whatever is cached + if self._replicator_mode: + return self._evaluate_flag(flag, cached_company, cached_user) + + # If we have all required entities cached, evaluate immediately + if (not needs_company or cached_company) and (not needs_user or cached_user): + return self._evaluate_flag(flag, cached_company, cached_user) + + if not self.is_connected(): + raise RuntimeError("Datastream not connected and required entities not in cache") + + # Fetch missing data in parallel + tasks = [] + if needs_company and not cached_company: + tasks.append(self.get_company(company_keys)) # type: ignore[arg-type] + else: + tasks.append(_resolved(cached_company)) + + if needs_user and not cached_user: + tasks.append(self.get_user(user_keys)) # type: ignore[arg-type] + else: + tasks.append(_resolved(cached_user)) + + company, user = await asyncio.gather(*tasks) + return self._evaluate_flag(flag, company, user) + + async def update_company_metrics(self, keys: Dict[str, str], event: str, quantity: int) -> None: + """Update company metrics locally in cache (for track events).""" + company = await self._get_company_from_cache(keys) + if company is None: + return + + updated = company.model_copy(deep=True) + if updated.metrics: + new_metrics = [ + metric.model_copy(update={"value": (metric.value or 0) + quantity}) + if metric.event_subtype == event else metric + for metric in updated.metrics + ] + updated = updated.model_copy(update={"metrics": new_metrics}) + + await self._cache_company(updated) + + def close(self) -> None: + """Gracefully close the datastream client.""" + self._logger.info("Closing DataStream client") + + if self._replicator_health_task is not None: + self._replicator_health_task.cancel() + self._replicator_health_task = None + + self._clear_pending_requests() + + if self._ws_client is not None: + # Schedule the async close — caller should await if needed + asyncio.ensure_future(self._ws_client.close()) + self._ws_client = None + + self._logger.info("DataStream client closed") + + async def close_async(self) -> None: + """Async version of close that awaits the websocket shutdown.""" + self._logger.info("Closing DataStream client") + + if self._replicator_health_task is not None: + self._replicator_health_task.cancel() + self._replicator_health_task = None + + self._clear_pending_requests() + + if self._ws_client is not None: + await self._ws_client.close() + self._ws_client = None + + self._logger.info("DataStream client closed") + + # ------------------------------------------------------------------ + # WebSocket callbacks + # ------------------------------------------------------------------ + + def _on_ws_connected(self) -> None: + if self._on_connected: + self._on_connected() + + def _on_ws_disconnected(self) -> None: + self._clear_pending_requests() + if self._on_disconnected: + self._on_disconnected() + + def _on_ws_error(self, error: Exception) -> None: + if self._on_error: + self._on_error(error) + + # ------------------------------------------------------------------ + # Message handling + # ------------------------------------------------------------------ + + async def _handle_message(self, message: DataStreamResp) -> None: + self._logger.debug( + "Processing datastream message: EntityType=%s, MessageType=%s", + message.entity_type, message.message_type, + ) + try: + if message.message_type == MessageType.ERROR.value: + await self._handle_error_message(message) + return + + et = message.entity_type + if et in (EntityType.COMPANY.value, "rulesengine.Company"): + await self._handle_company_message(message) + elif et in (EntityType.USER.value, "rulesengine.User"): + await self._handle_user_message(message) + elif et in (EntityType.FLAGS.value, "rulesengine.Flags"): + await self._handle_flags_message(message) + elif et in (EntityType.FLAG.value, "rulesengine.Flag"): + await self._handle_flag_message(message) + else: + self._logger.warning("Unknown entity type: %s", et) + except Exception as exc: + self._logger.error("Error processing datastream message: %s", exc) + if self._on_error: + self._on_error(exc if isinstance(exc, Exception) else Exception(str(exc))) + + async def _handle_company_message(self, message: DataStreamResp) -> None: + raw = message.data + if not raw: + return + + # For partial updates, we need the raw dict to merge into the existing model + if message.message_type == MessageType.PARTIAL.value: + partial_data = raw if isinstance(raw, dict) else raw.model_dump() + entity_id = partial_data.get("id") if isinstance(partial_data, dict) else getattr(partial_data, "id", None) + if not entity_id: + self._logger.warning("Partial company message missing id") + return + + rk = self._resource_id_cache_key(_PREFIX_COMPANY, entity_id) + raw_existing = await self._company_cache.get(rk) + if raw_existing is None: + self._logger.warning("Partial company update for unknown entity: %s", entity_id) + return + + existing = _validate(RulesengineCompany, raw_existing) + try: + company = partial_company(existing, partial_data) + except Exception as exc: + self._logger.error("Failed to merge partial company: %s", exc) + return + else: + company = _validate(RulesengineCompany, raw) + + if message.message_type == MessageType.DELETE.value: + await self._delete_entity( + company.id, company.keys, _PREFIX_COMPANY, self._company_cache, self._company_key_cache, + ) + return + + await self._cache_company(company) + self._notify_pending_company(company.keys or {}, company) + + async def _handle_user_message(self, message: DataStreamResp) -> None: + raw = message.data + if not raw: + return + + # For partial updates, we need the raw dict to merge into the existing model + if message.message_type == MessageType.PARTIAL.value: + partial_data = raw if isinstance(raw, dict) else raw.model_dump() + entity_id = partial_data.get("id") if isinstance(partial_data, dict) else getattr(partial_data, "id", None) + if not entity_id: + self._logger.warning("Partial user message missing id") + return + + rk = self._resource_id_cache_key(_PREFIX_USER, entity_id) + raw_existing = await self._user_cache.get(rk) + if raw_existing is None: + self._logger.warning("Partial user update for unknown entity: %s", entity_id) + return + + existing = _validate(RulesengineUser, raw_existing) + try: + user = partial_user(existing, partial_data) + except Exception as exc: + self._logger.error("Failed to merge partial user: %s", exc) + return + else: + user = _validate(RulesengineUser, raw) + + if message.message_type == MessageType.DELETE.value: + await self._delete_entity( + user.id, user.keys, _PREFIX_USER, self._user_cache, self._user_key_cache, + ) + return + + await self._cache_user(user) + self._notify_pending_user(user.keys or {}, user) + + async def _handle_flags_message(self, message: DataStreamResp) -> None: + raw_flags = message.data + if not isinstance(raw_flags, list): + self._logger.warning("Expected flags array in bulk flags message") + return + + cached_keys: List[str] = [] + for raw_flag in raw_flags: + flag = _validate(RulesengineFlag, raw_flag) + flag_key = flag.key + if not flag_key: + continue + ck = self._flag_cache_key(flag_key) + try: + await self._flag_cache.set(ck, flag) + cached_keys.append(ck) + except Exception as exc: + self._logger.warning("Failed to cache flag: %s", exc) + + # Delete flags not in the response + try: + await self._flag_cache.delete_missing(cached_keys, scan_pattern="flags:*") + except (NotImplementedError, Exception) as exc: + self._logger.debug("delete_missing not supported or failed: %s", exc) + + if self._pending_flags is not None and not self._pending_flags.done(): + self._pending_flags.set_result(True) + + async def _handle_flag_message(self, message: DataStreamResp) -> None: + raw = message.data + flag = _validate(RulesengineFlag, raw) + flag_key = flag.key + if not flag_key: + return + + ck = self._flag_cache_key(flag_key) + try: + if message.message_type == MessageType.DELETE.value: + await self._flag_cache.delete(ck) + elif message.message_type == MessageType.FULL.value: + await self._flag_cache.set(ck, flag) + except Exception as exc: + self._logger.warning("Failed to update flag cache: %s", exc) + + if self._pending_flags is not None and not self._pending_flags.done(): + self._pending_flags.set_result(True) + + async def _handle_error_message(self, message: DataStreamResp) -> None: + error_data = message.data + if isinstance(error_data, dict): + keys = error_data.get("keys") + entity_type = error_data.get("entity_type") + if keys and entity_type: + if entity_type in (EntityType.COMPANY.value, "rulesengine.Company"): + self._notify_pending_company(keys, None) + elif entity_type in (EntityType.USER.value, "rulesengine.User"): + self._notify_pending_user(keys, None) + + error_msg = error_data.get("error", "Unknown datastream error") + self._logger.warning("DataStream error received: %s", error_msg) + + async def _handle_connection_ready(self) -> None: + self._logger.info("DataStream connection is ready") + try: + # Only send the flags request — don't await the response here. + # The response will be processed by the message loop, which hasn't + # started yet (it begins after this handler returns). + loop = asyncio.get_running_loop() + self._pending_flags = loop.create_future() + await self._send_request(DataStreamReq(entity_type=EntityType.FLAGS)) + self._logger.debug("Sent initial flag data request") + except Exception as exc: + self._logger.error("Failed to request initial flag data: %s", exc) + self._pending_flags = None + raise + + # ------------------------------------------------------------------ + # Request sending + # ------------------------------------------------------------------ + + async def _send_request(self, request: DataStreamReq) -> None: + if self._ws_client is None or not self._ws_client.is_connected(): + raise RuntimeError("DataStream client is not connected") + + self._logger.debug( + "Sending datastream request: EntityType=%s, Keys=%s", + request.entity_type, request.keys, + ) + await self._ws_client.send_message(DataStreamBaseReq(data=request)) + + # ------------------------------------------------------------------ + # Cache helpers + # ------------------------------------------------------------------ + + async def _get_company_from_cache(self, keys: Dict[str, str]) -> Optional[RulesengineCompany]: + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_COMPANY, key, value) + try: + company_id = await self._company_key_cache.get(ck) + self._logger.debug("Company lookup key %s -> %s", ck, company_id) + if company_id: + rk = self._resource_id_cache_key(_PREFIX_COMPANY, company_id) + raw = await self._company_cache.get(rk) + self._logger.debug("Company ID key %s -> %s", rk, "hit" if raw is not None else "miss") + if raw is not None: + return _validate(RulesengineCompany, raw) + except Exception as exc: + self._logger.warning("Failed to retrieve company from cache: %s", exc) + return None + + async def _get_user_from_cache(self, keys: Dict[str, str]) -> Optional[RulesengineUser]: + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_USER, key, value) + try: + user_id = await self._user_key_cache.get(ck) + if user_id: + rk = self._resource_id_cache_key(_PREFIX_USER, user_id) + raw = await self._user_cache.get(rk) + if raw is not None: + return _validate(RulesengineUser, raw) + except Exception as exc: + self._logger.warning("Failed to retrieve user from cache: %s", exc) + return None + + async def _cache_company(self, company: RulesengineCompany) -> None: + keys = company.keys + company_id = company.id + if not keys: + return + + rk = self._resource_id_cache_key(_PREFIX_COMPANY, company_id) + + # Clean up stale lookup keys by diffing old vs new + raw = await self._company_cache.get(rk) + if raw is not None: + old = _validate(RulesengineCompany, raw) + old_keys = old.keys or {} + await self._delete_stale_lookup_keys( + self._company_key_cache, _PREFIX_COMPANY, old_keys, keys, + ) + + await self._company_cache.set(rk, company, self._cache_ttl) + + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_COMPANY, key, value) + try: + await self._company_key_cache.set(ck, company_id, self._cache_ttl) + except Exception as exc: + self._logger.warning("Failed to cache company key mapping '%s': %s", ck, exc) + + async def _cache_user(self, user: RulesengineUser) -> None: + keys = user.keys + user_id = user.id + if not keys: + return + + rk = self._resource_id_cache_key(_PREFIX_USER, user_id) + + # Clean up stale lookup keys by diffing old vs new + raw = await self._user_cache.get(rk) + if raw is not None: + old = _validate(RulesengineUser, raw) + old_keys = old.keys or {} + await self._delete_stale_lookup_keys( + self._user_key_cache, _PREFIX_USER, old_keys, keys, + ) + + await self._user_cache.set(rk, user, self._cache_ttl) + + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_USER, key, value) + try: + await self._user_key_cache.set(ck, user_id, self._cache_ttl) + except Exception as exc: + self._logger.warning("Failed to cache user key mapping '%s': %s", ck, exc) + + async def _delete_entity( + self, + entity_id: Optional[str], + message_keys: Optional[Dict[str, str]], + prefix: str, + entity_cache: AsyncCacheProvider[Any], + lookup_cache: AsyncCacheProvider[str], + ) -> None: + """Delete an entity and all its lookup keys from cache. + + Fetches the cached entity first to discover all lookup keys, + since the delete message may not include them all. + """ + all_keys = message_keys + if entity_id: + rk = self._resource_id_cache_key(prefix, entity_id) + cached = await entity_cache.get(rk) + if cached is not None: + if isinstance(cached, dict): + all_keys = cached.get("keys") or message_keys + else: + all_keys = cached.keys or message_keys + + if all_keys: + for key, value in all_keys.items(): + ck = self._resource_key_to_cache_key(prefix, key, value) + try: + await lookup_cache.delete(ck) + except Exception as exc: + self._logger.warning("Failed to delete %s key mapping: %s", prefix, exc) + + if entity_id: + rk = self._resource_id_cache_key(prefix, entity_id) + try: + await entity_cache.delete(rk) + except Exception as exc: + self._logger.warning("Failed to delete %s resource: %s", prefix, exc) + + async def _delete_stale_lookup_keys( + self, + lookup_cache: AsyncCacheProvider[str], + prefix: str, + old_keys: Dict[str, str], + new_keys: Dict[str, str], + ) -> None: + """Delete lookup cache entries for keys that are no longer present.""" + old_set = {(k, v) for k, v in old_keys.items()} + new_set = {(k, v) for k, v in new_keys.items()} + for key, value in old_set - new_set: + ck = self._resource_key_to_cache_key(prefix, key, value) + try: + await lookup_cache.delete(ck) + except Exception as exc: + self._logger.warning("Failed to delete stale lookup key '%s': %s", ck, exc) + + # ------------------------------------------------------------------ + # Cache key generation + # ------------------------------------------------------------------ + + def _flag_cache_key(self, key: str) -> str: + version = self._get_version_key() + return f"{_PREFIX_FLAGS}:{version}:{key.lower()}" + + def _resource_id_cache_key(self, resource_type: str, entity_id: str) -> str: + version = self._get_version_key() + return f"{resource_type}:{version}:{entity_id}" + + def _resource_key_to_cache_key(self, resource_type: str, key: str, value: str) -> str: + version = self._get_version_key() + return f"{resource_type}:{version}:{key.lower()}:{value.lower()}" + + def _get_version_key(self) -> str: + if self._replicator_mode and self._replicator_cache_version: + return self._replicator_cache_version + try: + if self._rules_engine.is_initialized(): + return self._rules_engine.get_version_key() + except Exception: + pass + if self._replicator_mode: + self._logger.warning( + "Replicator mode active but cache version unknown — " + "cache lookups will use fallback version '1' and likely miss" + ) + return "1" + + def _generate_company_cache_keys(self, keys: Dict[str, str]) -> List[str]: + return [self._resource_key_to_cache_key(_PREFIX_COMPANY, k, v) for k, v in keys.items()] + + def _generate_user_cache_keys(self, keys: Dict[str, str]) -> List[str]: + return [self._resource_key_to_cache_key(_PREFIX_USER, k, v) for k, v in keys.items()] + + # ------------------------------------------------------------------ + # Pending request management + # ------------------------------------------------------------------ + + def _notify_pending_company(self, keys: Dict[str, str], company: Any) -> None: + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_COMPANY, key, value) + futures = self._pending_company.pop(ck, []) + for fut in futures: + if not fut.done(): + if company is not None: + fut.set_result(company) + else: + fut.set_exception(RuntimeError("Company not found")) + + def _notify_pending_user(self, keys: Dict[str, str], user: Any) -> None: + for key, value in keys.items(): + ck = self._resource_key_to_cache_key(_PREFIX_USER, key, value) + futures = self._pending_user.pop(ck, []) + for fut in futures: + if not fut.done(): + if user is not None: + fut.set_result(user) + else: + fut.set_exception(RuntimeError("User not found")) + + def _cleanup_pending_company(self, cache_keys: List[str], future: asyncio.Future[Any]) -> None: + for ck in cache_keys: + futures = self._pending_company.get(ck) + if futures: + try: + futures.remove(future) + except ValueError: + pass + if not futures: + del self._pending_company[ck] + + def _cleanup_pending_user(self, cache_keys: List[str], future: asyncio.Future[Any]) -> None: + for ck in cache_keys: + futures = self._pending_user.get(ck) + if futures: + try: + futures.remove(future) + except ValueError: + pass + if not futures: + del self._pending_user[ck] + + def _clear_pending_requests(self) -> None: + for futures in self._pending_company.values(): + for fut in futures: + if not fut.done(): + fut.set_exception(RuntimeError("DataStream client disconnected")) + self._pending_company.clear() + + for futures in self._pending_user.values(): + for fut in futures: + if not fut.done(): + fut.set_exception(RuntimeError("DataStream client disconnected")) + self._pending_user.clear() + + if self._pending_flags is not None and not self._pending_flags.done(): + self._pending_flags.set_result(False) + self._pending_flags = None + + # ------------------------------------------------------------------ + # Flag evaluation + # ------------------------------------------------------------------ + + def _evaluate_flag( + self, + flag: RulesengineFlag, + company: Optional[RulesengineCompany], + user: Optional[RulesengineUser], + ) -> RulesengineCheckFlagResult: + default_value = flag.default_value + + try: + if self._rules_engine.is_initialized(): + return self._rules_engine.check_flag(flag, company, user) + else: + self._logger.warning("Rules engine not initialized, using default flag value") + return self._make_default_result(flag, company, user, default_value, "RULES_ENGINE_UNAVAILABLE") + except Exception as exc: + self._logger.error("Rules engine evaluation failed: %s", exc) + return self._make_default_result(flag, company, user, default_value, "RULES_ENGINE_ERROR") + + @staticmethod + def _make_default_result( + flag: RulesengineFlag, + company: Optional[RulesengineCompany], + user: Optional[RulesengineUser], + value: bool, + reason: str, + ) -> RulesengineCheckFlagResult: + return RulesengineCheckFlagResult( + value=value, + reason=reason, + flag_key=flag.key, + flag_id=flag.id, + company_id=company.id if company else None, + user_id=user.id if user else None, + ) + + # ------------------------------------------------------------------ + # Replicator health checking + # ------------------------------------------------------------------ + + def _start_replicator_health_check(self) -> None: + if not self._replicator_health_url: + return + self._logger.info( + "Starting replicator health check: url=%s, interval=%dms", + self._replicator_health_url, self._replicator_health_check_ms, + ) + self._replicator_health_task = asyncio.ensure_future(self._replicator_health_loop()) + + async def _replicator_health_loop(self) -> None: + interval_s = self._replicator_health_check_ms / 1000 + while True: + await self._check_replicator_health() + try: + await asyncio.sleep(interval_s) + except asyncio.CancelledError: + break + + async def _check_replicator_health(self) -> None: + if not self._replicator_health_url: + return + try: + import httpx + + async with httpx.AsyncClient(timeout=REPLICATOR_HEALTH_TIMEOUT_S) as client: + resp = await client.get(self._replicator_health_url) + resp.raise_for_status() + health_data = resp.json() + + self._logger.debug("Replicator health response: %s", health_data) + + was_ready = self._replicator_ready + self._replicator_ready = health_data.get("ready", False) + + new_version = health_data.get("cache_version") or health_data.get("cacheVersion") + if new_version and new_version != self._replicator_cache_version: + old = self._replicator_cache_version + self._replicator_cache_version = new_version + self._logger.info("Cache version changed from %s to %s", old, new_version) + + if self._replicator_ready and not was_ready: + self._logger.info("External replicator is now ready") + if self._on_replicator_health_changed: + self._on_replicator_health_changed(True) + elif not self._replicator_ready and was_ready: + self._logger.info("External replicator is no longer ready") + if self._on_replicator_health_changed: + self._on_replicator_health_changed(False) + + except Exception as exc: + if self._replicator_ready: + self._replicator_ready = False + self._logger.info("External replicator is no longer ready") + if self._on_replicator_health_changed: + self._on_replicator_health_changed(False) + self._logger.debug("Replicator health check failed: %s", exc) + + async def get_replicator_cache_version_async(self, timeout_s: float = REPLICATOR_CACHE_VERSION_TIMEOUT_S) -> Optional[str]: + """Attempt to fetch cache version immediately if not already available.""" + if self._replicator_cache_version: + return self._replicator_cache_version + + if self._replicator_mode and self._replicator_health_url: + try: + import httpx + + async with httpx.AsyncClient(timeout=timeout_s) as client: + resp = await client.get(self._replicator_health_url) + if resp.status_code == 200: + data = resp.json() + version = data.get("cache_version") or data.get("cacheVersion") + if version: + self._replicator_cache_version = version + return version + except Exception as exc: + self._logger.debug("Failed to fetch replicator cache version: %s", exc) + + return None + + +async def _resolved(value: Any) -> Any: + """Helper that acts like an immediately-resolved coroutine.""" + return value diff --git a/src/schematic/datastream/merge.py b/src/schematic/datastream/merge.py new file mode 100644 index 0000000..139fe0a --- /dev/null +++ b/src/schematic/datastream/merge.py @@ -0,0 +1,133 @@ +from __future__ import annotations + +from typing import Any, Dict, List, Optional, Tuple + +from ..types.rulesengine_company import RulesengineCompany +from ..types.rulesengine_company_metric import RulesengineCompanyMetric +from ..types.rulesengine_user import RulesengineUser + + +def extract_id(data: Any) -> Optional[str]: + """Extract the 'id' field from a dict or Pydantic model.""" + if isinstance(data, dict): + return data.get("id") + return getattr(data, "id", None) + + +def partial_company(existing: RulesengineCompany, partial: Dict[str, Any]) -> RulesengineCompany: + """Merge a partial update dict into an existing Company. + + Only fields present in `partial` are applied. Maps (keys, credit_balances) + merge additively. Metrics are upserted by (event_subtype, period, month_reset). + All other fields replace the existing value. The original is not mutated. + """ + if "id" not in partial: + raise ValueError("partial company message missing required field: id") + + updates: Dict[str, Any] = {} + + for key, value in partial.items(): + if key == "keys": + merged_keys = dict(existing.keys) if existing.keys else {} + merged_keys.update(value or {}) + updates["keys"] = merged_keys + elif key == "credit_balances": + merged_cb = dict(existing.credit_balances) if existing.credit_balances else {} + merged_cb.update(value or {}) + updates["credit_balances"] = merged_cb + elif key == "metrics": + incoming = _parse_metrics(value) + existing_metrics = [m.model_dump() for m in (existing.metrics or [])] + updates["metrics"] = _upsert_metrics(existing_metrics, incoming) + else: + updates[key] = value + + base = existing.model_dump() + base.update(updates) + return RulesengineCompany.model_validate(base) + + +def partial_user(existing: RulesengineUser, partial: Dict[str, Any]) -> RulesengineUser: + """Merge a partial update dict into an existing User. + + Only fields present in `partial` are applied. Keys map merges additively. + All other fields replace the existing value. The original is not mutated. + """ + if "id" not in partial: + raise ValueError("partial user message missing required field: id") + + updates: Dict[str, Any] = {} + + for key, value in partial.items(): + if key == "keys": + merged_keys = dict(existing.keys) if existing.keys else {} + merged_keys.update(value or {}) + updates["keys"] = merged_keys + else: + updates[key] = value + + base = existing.model_dump() + base.update(updates) + return RulesengineUser.model_validate(base) + + +def deep_copy_company(company: Optional[RulesengineCompany]) -> Optional[RulesengineCompany]: + """Create a deep copy of a Company. Returns None if input is None.""" + if company is None: + return None + return company.model_copy(deep=True) + + +def deep_copy_user(user: Optional[RulesengineUser]) -> Optional[RulesengineUser]: + """Create a deep copy of a User. Returns None if input is None.""" + if user is None: + return None + return user.model_copy(deep=True) + + +def _metric_key(metric: Any) -> Tuple[str, str, str]: + """Build the composite key used for metric upsert matching.""" + if isinstance(metric, dict): + return ( + metric.get("event_subtype", ""), + metric.get("period", ""), + metric.get("month_reset", ""), + ) + return ( + getattr(metric, "event_subtype", ""), + str(getattr(metric, "period", "")), + str(getattr(metric, "month_reset", "")), + ) + + +def _parse_metrics(raw: Any) -> List[Any]: + """Normalise incoming metrics to a list.""" + if raw is None: + return [] + if isinstance(raw, list): + return raw + return [raw] + + +def _upsert_metrics(existing: List[Any], incoming: List[Any]) -> List[Any]: + """Merge incoming metrics into existing ones. + + Metrics are matched by (event_subtype, period, month_reset). + Matches are replaced in place; new metrics are appended. + """ + result = list(existing) + index: Dict[Tuple[str, str, str], int] = {} + for i, m in enumerate(result): + if m is not None: + index[_metric_key(m)] = i + + for m in incoming: + if m is None: + continue + k = _metric_key(m) + if k in index: + result[index[k]] = m + else: + result.append(m) + + return result diff --git a/src/schematic/datastream/rules_engine.py b/src/schematic/datastream/rules_engine.py new file mode 100644 index 0000000..7f3dc1b --- /dev/null +++ b/src/schematic/datastream/rules_engine.py @@ -0,0 +1,176 @@ +from __future__ import annotations + +import ctypes +import json +import logging +from pathlib import Path +from typing import Any, Optional + +from ..types.rulesengine_check_flag_result import RulesengineCheckFlagResult +from ..types.rulesengine_company import RulesengineCompany +from ..types.rulesengine_flag import RulesengineFlag +from ..types.rulesengine_user import RulesengineUser + +logger = logging.getLogger(__name__) + +# Path to the WASM binary shipped alongside this module +_WASM_PATH = Path(__file__).parent / "wasm" / "rulesengine.wasm" + + +class RulesEngineClient: + """Wrapper around the Rust WASM rules engine for local flag evaluation. + + Uses ``wasmtime`` to load and execute the raw WASM binary. The WASM + module exposes a ``checkFlagCombined`` function that accepts a single + JSON envelope ``{"flag": ..., "company": ..., "user": ...}`` and returns + the evaluation result. All WASM memory management is handled internally + via the module's ``alloc``/``dealloc`` exports. + + Usage:: + + engine = RulesEngineClient() + await engine.initialize() + result = engine.check_flag(flag, company, user) + """ + + def __init__(self, *, wasm_path: Optional[str] = None) -> None: + self._wasm_path = Path(wasm_path) if wasm_path else _WASM_PATH + self._initialized = False + # wasmtime objects — set during initialize() + self._store: Any = None + self._instance: Any = None + self._memory: Any = None + self._alloc_fn: Any = None + self._dealloc_fn: Any = None + self._check_flag_fn: Any = None + self._get_result_json_fn: Any = None + self._get_result_json_length_fn: Any = None + self._get_version_key_fn: Any = None + + async def initialize(self) -> None: + """Load and instantiate the WASM module. Safe to call multiple times.""" + if self._initialized: + return + + try: + import wasmtime # type: ignore[import-untyped] + except ImportError: + raise ImportError( + "wasmtime is required for the rules engine. " + "Install it with: pip install 'schematichq[rulesengine]' or pip install wasmtime" + ) + + if not self._wasm_path.exists(): + raise FileNotFoundError( + f"WASM binary not found at {self._wasm_path}. " + "Ensure the rules engine WASM has been deployed to this SDK." + ) + + engine = wasmtime.Engine() + module = wasmtime.Module.from_file(engine, str(self._wasm_path)) + linker = wasmtime.Linker(engine) + linker.define_wasi() + + wasi_config = wasmtime.WasiConfig() + self._store = wasmtime.Store(engine) + self._store.set_wasi(wasi_config) + + self._instance = linker.instantiate(self._store, module) + exports = self._instance.exports(self._store) + + self._memory = exports.get("memory") + self._alloc_fn = exports.get("alloc") + self._dealloc_fn = exports.get("dealloc") + self._check_flag_fn = exports.get("checkFlagCombined") + self._get_result_json_fn = exports.get("getResultJson") + self._get_result_json_length_fn = exports.get("getResultJsonLength") + self._get_version_key_fn = exports.get("get_version_key_wasm") + + if self._memory is None: + raise RuntimeError("WASM module does not export 'memory'") + if self._alloc_fn is None: + raise RuntimeError("WASM module does not export 'alloc'") + if self._check_flag_fn is None: + raise RuntimeError("WASM module does not export 'checkFlagCombined'") + + self._initialized = True + logger.debug("Rules engine WASM initialized (version: %s)", self.get_version_key()) + + def is_initialized(self) -> bool: + return self._initialized + + def check_flag( + self, + flag: RulesengineFlag, + company: Optional[RulesengineCompany] = None, + user: Optional[RulesengineUser] = None, + ) -> RulesengineCheckFlagResult: + """Evaluate a flag using the WASM rules engine. + + Accepts Fern-generated Pydantic models (or plain dicts). Serialises + them into a single JSON envelope, passes it to the WASM module, and + returns a ``RulesengineCheckFlagResult``. + """ + self._ensure_initialized() + + envelope = { + "flag": flag.model_dump(exclude_none=True, mode="json"), + "company": company.model_dump(exclude_none=True, mode="json") if company else None, + "user": user.model_dump(exclude_none=True, mode="json") if user else None, + } + + result_json = self._call_wasm(json.dumps(envelope)) + result_data = json.loads(result_json) + return RulesengineCheckFlagResult(**result_data) + + def get_version_key(self) -> str: + """Get the version key from the WASM rules engine. + + Used for cache key generation to ensure cache invalidation on engine updates. + """ + self._ensure_initialized() + + if self._get_version_key_fn is None: + return "1" + + ptr = self._get_version_key_fn(self._store) + return self._read_memory(ptr, 8).decode("utf-8") + + # ------------------------------------------------------------------ + # Internal helpers + # ------------------------------------------------------------------ + + def _ensure_initialized(self) -> None: + if not self._initialized: + raise RuntimeError("Rules engine not initialized. Call initialize() first.") + + def _call_wasm(self, input_json: str) -> str: + """Write *input_json* into WASM memory, invoke the engine, and return + the result JSON string. All memory is allocated/freed via the WASM + module's own ``alloc``/``dealloc`` exports.""" + + data = input_json.encode("utf-8") + length = len(data) + + # Allocate a buffer inside WASM memory and copy our JSON into it + ptr = self._alloc_fn(self._store, length) + try: + base = ctypes.addressof(self._memory.data_ptr(self._store).contents) + ctypes.memmove(base + ptr, data, length) + + result_len = self._check_flag_fn(self._store, ptr, length) + if result_len < 0: + raise RuntimeError("WASM checkFlagCombined returned error code") + finally: + self._dealloc_fn(self._store, ptr, length) + + # Read the result (owned by WASM thread-local, no need to free) + result_ptr = self._get_result_json_fn(self._store) + actual_len = self._get_result_json_length_fn(self._store) + return self._read_memory(result_ptr, actual_len).decode("utf-8") + + def _read_memory(self, ptr: int, length: int) -> bytes: + """Read *length* bytes from WASM linear memory at *ptr*.""" + base = ctypes.addressof(self._memory.data_ptr(self._store).contents) + src = (ctypes.c_ubyte * length).from_address(base + ptr) + return bytes(src) diff --git a/src/schematic/datastream/types.py b/src/schematic/datastream/types.py index 534fb9c..a7a6c97 100644 --- a/src/schematic/datastream/types.py +++ b/src/schematic/datastream/types.py @@ -6,12 +6,10 @@ class EntityType(str, enum.Enum): - COMPANY = "rulesengine.Company" - COMPANIES = "rulesengine.Companies" - USER = "rulesengine.User" - USERS = "rulesengine.Users" - FLAG = "rulesengine.Flag" - FLAGS = "rulesengine.Flags" + COMPANY = "company" + USER = "user" + FLAG = "flag" + FLAGS = "flags" class MessageType(str, enum.Enum): @@ -22,15 +20,24 @@ class MessageType(str, enum.Enum): UNKNOWN = "unknown" +class Action(str, enum.Enum): + START = "start" + STOP = "stop" + + @dataclass class DataStreamReq: """Request message sent to the datastream.""" entity_type: EntityType keys: Optional[Dict[str, str]] = None + action: Action = Action.START def to_dict(self) -> Dict[str, Any]: - d: Dict[str, Any] = {"entity_type": self.entity_type.value} + d: Dict[str, Any] = { + "action": self.action.value, + "entity_type": self.entity_type.value, + } if self.keys is not None: d["keys"] = self.keys return d diff --git a/src/schematic/datastream/wasm/rulesengine.wasm b/src/schematic/datastream/wasm/rulesengine.wasm new file mode 100755 index 0000000000000000000000000000000000000000..7a64e670fd77a4b2752f2cfed3f85f407242ea2a GIT binary patch literal 615067 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

u(_A44<&1yE3 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�F_72+e@h%qB-& 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 literal 0 HcmV?d00001 diff --git a/src/schematic/datastream/websocket_client.py b/src/schematic/datastream/websocket_client.py index 3cca4cd..29d4797 100644 --- a/src/schematic/datastream/websocket_client.py +++ b/src/schematic/datastream/websocket_client.py @@ -7,7 +7,7 @@ import logging import random from dataclasses import dataclass -from typing import AsyncIterator, Awaitable, Callable, Dict, Optional, Protocol, Union +from typing import Any, Awaitable, Callable, Dict, Optional, Union from urllib.parse import urlparse, urlunparse import websockets @@ -15,14 +15,6 @@ from .types import DataStreamBaseReq, DataStreamResp -class _WebSocketProtocol(Protocol): - """Structural interface for the websocket connection object.""" - - async def send(self, message: Union[str, bytes]) -> None: ... - - async def close(self) -> None: ... - - def __aiter__(self) -> AsyncIterator[Union[str, bytes]]: ... # Connection timing constants (seconds) WRITE_WAIT = 10.0 @@ -145,7 +137,7 @@ def __init__(self, options: ClientOptions) -> None: self._on_error = options.on_error # Connection state - self._ws: Optional[_WebSocketProtocol] = None + self._ws: Any = None self._connected: bool = False self._ready: bool = False @@ -153,6 +145,7 @@ def __init__(self, options: ClientOptions) -> None: self._should_reconnect: bool = False self._reconnect_attempts: int = 0 self._task: Optional[asyncio.Task[None]] = None + self._ping_task: Optional[asyncio.Task[None]] = None def start(self) -> None: """Begin the WebSocket connection loop as a background asyncio task.""" @@ -215,10 +208,13 @@ async def _connect_and_read(self) -> None: try: async with websockets.connect( self._url, - extra_headers=self._headers, + additional_headers=self._headers, open_timeout=CONNECTION_TIMEOUT, - ping_interval=PING_PERIOD, - ping_timeout=PONG_WAIT, + # Disable the library's built-in keepalive — we manage + # ping/pong ourselves to match the Node SDK behaviour and + # avoid conflicts with the Go server's gorilla/websocket. + ping_interval=None, + ping_timeout=None, ) as ws: self._ws = ws self._reconnect_attempts = 0 @@ -236,8 +232,12 @@ async def _connect_and_read(self) -> None: self._set_ready(True) self._logger.debug("WebSocket client is ready") - async for raw_message in ws: - await self._handle_message(raw_message) + self._start_ping_pong() + try: + async for raw_message in ws: + await self._handle_message(raw_message) + finally: + self._stop_ping_pong() self._logger.info("WebSocket connection closed") @@ -272,6 +272,60 @@ async def _connect_and_read(self) -> None: except asyncio.CancelledError: break + # ------------------------------------------------------------------ + # Keepalive ping/pong + # ------------------------------------------------------------------ + + def _start_ping_pong(self) -> None: + """Start the application-level ping/pong keepalive loop.""" + self._logger.debug("Starting ping/pong keepalive mechanism") + self._ping_task = asyncio.ensure_future(self._ping_loop()) + + def _stop_ping_pong(self) -> None: + """Stop the keepalive loop.""" + if self._ping_task is not None: + self._ping_task.cancel() + self._ping_task = None + + async def _ping_loop(self) -> None: + """Send pings every PING_PERIOD seconds, close if multiple consecutive pongs are missed. + + Pong frames are only processed by the websockets library during recv(), + so if the message handler is busy, a single pong may be delayed. We + tolerate up to 2 consecutive missed pongs before closing. + """ + missed = 0 + max_missed = 2 + + while self._connected and self._ws is not None: + try: + await asyncio.sleep(PING_PERIOD) + except asyncio.CancelledError: + return + + if not self._connected or self._ws is None: + return + + try: + pong_waiter = await self._ws.ping() + await asyncio.wait_for(pong_waiter, timeout=PONG_WAIT) + missed = 0 + self._logger.debug("Pong received from server") + except asyncio.TimeoutError: + missed += 1 + self._logger.warning("Pong timeout (%d/%d)", missed, max_missed) + if missed >= max_missed: + self._logger.warning("Max pong timeouts reached — closing connection") + self._set_connected(False) + if self._ws is not None: + await self._ws.close() + return + except asyncio.CancelledError: + return + except Exception as exc: + self._logger.debug("Ping failed: %s", exc) + return + # ------------------------------------------------------------------ # Message handling # ------------------------------------------------------------------ diff --git a/tests/custom/test_client.py b/tests/custom/test_client.py index c3fdec5..ebd503e 100644 --- a/tests/custom/test_client.py +++ b/tests/custom/test_client.py @@ -1,5 +1,5 @@ import unittest -from unittest.mock import MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest from httpx import AsyncClient, Client @@ -7,9 +7,11 @@ from schematic.client import ( AsyncSchematic, AsyncSchematicConfig, + CheckFlagOptions, Schematic, SchematicConfig, ) +from schematic.types import CheckFlagResponseData class TestSchematic(unittest.TestCase): @@ -44,6 +46,89 @@ def test_check_flag_online(self): ) self.assertTrue(result) + def test_check_flag_with_entitlement_offline(self): + self.schematic.offline = True + self.schematic.flag_defaults = {"test_flag": True} + result = self.schematic.check_flag_with_entitlement( + "test_flag", + company={"id": "company_id"}, + user={"id": "user_id"}, + ) + self.assertIsInstance(result, CheckFlagResponseData) + self.assertTrue(result.value) + self.assertEqual(result.flag, "test_flag") + self.assertEqual(result.reason, "flag default") + + def test_check_flag_with_entitlement_online(self): + self.schematic.offline = False + mock_data = CheckFlagResponseData( + value=True, + company_id="comp_123", + entitlement=None, + error=None, + flag="test_flag", + flag_id="flag_123", + reason="rule_match", + rule_id="rule_123", + rule_type="override", + user_id="user_123", + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag_with_entitlement( + "test_flag", + company={"id": "company_id"}, + user={"id": "user_id"}, + ) + self.assertIsInstance(result, CheckFlagResponseData) + self.assertTrue(result.value) + self.assertEqual(result.company_id, "comp_123") + self.assertEqual(result.reason, "rule_match") + self.assertEqual(result.rule_id, "rule_123") + + def test_check_flag_with_options_default_value(self): + self.schematic.offline = True + options = CheckFlagOptions(default_value=True) + result = self.schematic.check_flag("missing_flag", options=options) + self.assertTrue(result) + + def test_check_flag_with_options_callable_default(self): + self.schematic.offline = True + options = CheckFlagOptions(default_value=lambda: True) + result = self.schematic.check_flag("missing_flag", options=options) + self.assertTrue(result) + + def test_check_flag_caches_full_response(self): + """Verify that cache stores the full response, not just a bool.""" + self.schematic.offline = False + mock_data = CheckFlagResponseData( + value=True, + company_id="comp_123", + entitlement=None, + error=None, + flag="test_flag", + flag_id="flag_123", + reason="rule_match", + rule_id="rule_123", + rule_type=None, + user_id=None, + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + + # First call populates cache + result1 = self.schematic.check_flag_with_entitlement("test_flag") + self.assertEqual(result1.company_id, "comp_123") + + # Second call should hit cache + result2 = self.schematic.check_flag_with_entitlement("test_flag") + self.assertEqual(result2.company_id, "comp_123") + + # API should only have been called once + self.schematic.features.check_flag.assert_called_once() + def test_identify(self): with patch.object(self.schematic.event_buffer, "push") as mock_push: self.schematic.identify( @@ -61,6 +146,15 @@ def test_track(self): ) mock_push.assert_called_once() + def test_track_with_quantity(self): + with patch.object(self.schematic.event_buffer, "push") as mock_push: + self.schematic.track( + event="api-call", + company={"id": "company_id"}, + quantity=5, + ) + mock_push.assert_called_once() + def tearDown(self): self.schematic.event_buffer.stop() @@ -102,6 +196,50 @@ async def test_check_flag_online(self): ) assert result + async def test_check_flag_with_entitlement_offline(self): + self.async_schematic.offline = True + self.async_schematic.flag_defaults = {"test_flag": True} + result = await self.async_schematic.check_flag_with_entitlement( + "test_flag", + company={"id": "company_id"}, + ) + assert isinstance(result, CheckFlagResponseData) + assert result.value is True + assert result.flag == "test_flag" + assert result.reason == "flag default" + + async def test_check_flag_with_entitlement_online(self): + self.async_schematic.offline = False + mock_data = CheckFlagResponseData( + value=True, + company_id="comp_123", + entitlement=None, + error=None, + flag="test_flag", + flag_id="flag_123", + reason="rule_match", + rule_id="rule_123", + rule_type="override", + user_id="user_123", + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag_with_entitlement( + "test_flag", + company={"id": "company_id"}, + ) + assert isinstance(result, CheckFlagResponseData) + assert result.value is True + assert result.company_id == "comp_123" + assert result.reason == "rule_match" + + async def test_check_flag_with_options(self): + self.async_schematic.offline = True + options = CheckFlagOptions(default_value=True) + result = await self.async_schematic.check_flag("missing_flag", options=options) + assert result is True + async def test_identify(self): with patch.object(self.async_schematic.event_buffer, "push") as mock_push: await self.async_schematic.identify( diff --git a/tests/datastream/__init__.py b/tests/datastream/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/datastream/test_cache.py b/tests/datastream/test_cache.py new file mode 100644 index 0000000..f95f54a --- /dev/null +++ b/tests/datastream/test_cache.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import asyncio +import time + +import pytest + +from schematic.cache import AsyncCacheProvider as CacheProvider, AsyncLocalCache as LocalCache + + +class TestLocalCacheGet: + async def test_returns_none_for_missing_key(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + assert await cache.get("nonexistent") is None + + async def test_returns_stored_value(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.set("key1", "value1") + assert await cache.get("key1") == "value1" + + async def test_returns_none_for_expired_item(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=1) # 1ms TTL + await cache.set("key1", "value1") + await asyncio.sleep(0.01) # Wait for expiration + assert await cache.get("key1") is None + + +class TestLocalCacheSet: + async def test_overwrites_existing_value(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.set("key1", "value1") + await cache.set("key1", "value2") + assert await cache.get("key1") == "value2" + + async def test_respects_max_items_with_lru_eviction(self) -> None: + cache: LocalCache[str] = LocalCache(max_items=2, ttl=5000) + await cache.set("a", "1") + await cache.set("b", "2") + # Access 'a' to make it recently used + await cache.get("a") + # Adding 'c' should evict 'b' (least recently used) + await cache.set("c", "3") + assert await cache.get("a") == "1" + assert await cache.get("b") is None + assert await cache.get("c") == "3" + + async def test_disabled_cache_when_max_items_zero(self) -> None: + cache: LocalCache[str] = LocalCache(max_items=0, ttl=5000) + await cache.set("key1", "value1") + assert await cache.get("key1") is None + + async def test_ttl_override(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.set("key1", "value1", ttl=1) # 1ms override + await asyncio.sleep(0.01) + assert await cache.get("key1") is None + + +class TestLocalCacheDelete: + async def test_deletes_existing_key(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.set("key1", "value1") + await cache.delete("key1") + assert await cache.get("key1") is None + + async def test_no_error_deleting_nonexistent_key(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.delete("nonexistent") # Should not raise + + +class TestLocalCacheDeleteMissing: + async def test_removes_keys_not_in_keep_list(self) -> None: + cache: LocalCache[str] = LocalCache(ttl=5000) + await cache.set("a", "1") + await cache.set("b", "2") + await cache.set("c", "3") + await cache.delete_missing(["a", "c"]) + assert await cache.get("a") == "1" + assert await cache.get("b") is None + assert await cache.get("c") == "3" + + +class TestCacheProviderInterface: + async def test_raises_not_implemented(self) -> None: + provider: CacheProvider[str] = CacheProvider() + with pytest.raises(NotImplementedError): + await provider.get("key") + with pytest.raises(NotImplementedError): + await provider.set("key", "value") + with pytest.raises(NotImplementedError): + await provider.delete("key") + with pytest.raises(NotImplementedError): + await provider.delete_missing(["key"]) diff --git a/tests/datastream/test_datastream_client.py b/tests/datastream/test_datastream_client.py new file mode 100644 index 0000000..c7462cb --- /dev/null +++ b/tests/datastream/test_datastream_client.py @@ -0,0 +1,358 @@ +from __future__ import annotations + +import asyncio +import logging +from typing import Any, Dict, List, Optional +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest + +from schematic.cache import AsyncCacheProvider as CacheProvider, AsyncLocalCache as LocalCache +from schematic.datastream.datastream_client import DataStreamClient, DataStreamClientOptions +from schematic.datastream.types import DataStreamResp, EntityType, MessageType +from schematic.types import CheckFlagRequestBody, RulesengineCheckFlagResult + + +class MockCacheProvider(CacheProvider[Any]): + """Simple in-memory cache for testing.""" + + def __init__(self) -> None: + self._store: Dict[str, Any] = {} + + async def get(self, key: str) -> Optional[Any]: + return self._store.get(key) + + async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None: + self._store[key] = value + + async def delete(self, key: str) -> None: + self._store.pop(key, None) + + async def delete_missing(self, keys_to_keep: List[str], *, scan_pattern: Optional[str] = None) -> None: + keep = set(keys_to_keep) + to_delete = [k for k in self._store if k not in keep] + for k in to_delete: + del self._store[k] + + +@pytest.fixture +def logger() -> logging.Logger: + return logging.getLogger("test_datastream") + + +class TestDataStreamClientInit: + def test_replicator_mode_requires_cache_providers(self, logger: logging.Logger) -> None: + with pytest.raises(ValueError, match="Replicator mode requires"): + DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + )) + + def test_replicator_mode_accepts_custom_cache(self, logger: logging.Logger) -> None: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + assert client.is_replicator_mode() + assert not client.is_connected() + + def test_normal_mode_defaults(self, logger: logging.Logger) -> None: + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + base_url="https://api.schematichq.com", + logger=logger, + )) + assert not client.is_replicator_mode() + assert not client.is_connected() + + +class TestDataStreamClientReplicatorMode: + @pytest.fixture + def client(self, logger: logging.Logger) -> DataStreamClient: + cache = MockCacheProvider() + return DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + + async def test_get_company_raises_when_not_cached(self, client: DataStreamClient) -> None: + with pytest.raises(RuntimeError, match="not found in cache"): + await client.get_company({"id": "co_123"}) + + async def test_get_user_raises_when_not_cached(self, client: DataStreamClient) -> None: + with pytest.raises(RuntimeError, match="not found in cache"): + await client.get_user({"id": "usr_123"}) + + +class TestDataStreamClientMessageHandling: + @pytest.fixture + def client_with_cache(self, logger: logging.Logger) -> tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider]: + company_cache = MockCacheProvider() + user_cache = MockCacheProvider() + flag_cache = MockCacheProvider() + lookup_cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=company_cache, + company_lookup_cache=lookup_cache, + user_cache=user_cache, + user_lookup_cache=lookup_cache, + flag_cache=flag_cache, + )) + return client, company_cache, user_cache, flag_cache + + async def test_handle_company_message_caches_data( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, company_cache, _, _ = client_with_cache + msg = DataStreamResp( + data={ + "id": "co_123", + "keys": {"slug": "acme"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": [], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.FULL.value, + ) + await client._handle_message(msg) + + # Company should be retrievable from cache + company = await client._get_company_from_cache({"slug": "acme"}) + assert company is not None + assert company.id == "co_123" + + async def test_handle_user_message_caches_data( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, _, user_cache, _ = client_with_cache + msg = DataStreamResp( + data={ + "id": "usr_456", + "keys": {"email": "test@example.com"}, + "account_id": "acc_1", + "environment_id": "env_1", + "rules": [], + "traits": [], + }, + entity_type=EntityType.USER.value, + message_type=MessageType.FULL.value, + ) + await client._handle_message(msg) + + user = await client._get_user_from_cache({"email": "test@example.com"}) + assert user is not None + assert user.id == "usr_456" + + async def test_handle_flags_message_caches_all_flags( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, _, _, flag_cache = client_with_cache + flags = [ + {"key": "flag-a", "id": "f1", "default_value": True, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + {"key": "flag-b", "id": "f2", "default_value": False, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + ] + msg = DataStreamResp( + data=flags, + entity_type=EntityType.FLAGS.value, + message_type=MessageType.FULL.value, + ) + await client._handle_message(msg) + + flag_a = await client.get_flag("flag-a") + flag_b = await client.get_flag("flag-b") + assert flag_a is not None + assert flag_a.key == "flag-a" + assert flag_b is not None + assert flag_b.key == "flag-b" + + async def test_handle_flag_delete( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, _, _, flag_cache = client_with_cache + + # First add a flag + msg = DataStreamResp( + data={"key": "flag-x", "id": "fx", "default_value": True, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + entity_type=EntityType.FLAG.value, + message_type=MessageType.FULL.value, + ) + await client._handle_message(msg) + assert await client.get_flag("flag-x") is not None + + # Then delete it + msg = DataStreamResp( + data={"key": "flag-x", "id": "fx", "default_value": False, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + entity_type=EntityType.FLAG.value, + message_type=MessageType.DELETE.value, + ) + await client._handle_message(msg) + assert await client.get_flag("flag-x") is None + + async def test_handle_company_delete( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, company_cache, _, _ = client_with_cache + + # Add company + msg = DataStreamResp( + data={ + "id": "co_del", + "keys": {"slug": "delete-me"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": [], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.FULL.value, + ) + await client._handle_message(msg) + assert await client._get_company_from_cache({"slug": "delete-me"}) is not None + + # Delete company + msg = DataStreamResp( + data={ + "id": "co_del", + "keys": {"slug": "delete-me"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": [], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.DELETE.value, + ) + await client._handle_message(msg) + assert await client._get_company_from_cache({"slug": "delete-me"}) is None + + async def test_handle_error_message( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider, MockCacheProvider, MockCacheProvider], + ) -> None: + client, _, _, _ = client_with_cache + msg = DataStreamResp( + data={"error": "test error", "keys": {"id": "co_err"}, "entity_type": EntityType.COMPANY.value}, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.ERROR.value, + ) + # Should not raise + await client._handle_message(msg) + + +class TestDataStreamClientClose: + async def test_close_cleans_up(self, logger: logging.Logger) -> None: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + client.close() # Should not raise + + +class TestDataStreamClientCacheKeys: + def test_flag_cache_key_uses_version(self, logger: logging.Logger) -> None: + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + base_url="https://api.schematichq.com", + logger=logger, + )) + key = client._flag_cache_key("Premium-Feature") + # Should be lowercased and include version key + assert "premium-feature" in key + assert key.startswith("flags:") + + def test_resource_key_to_cache_key_lowercases(self, logger: logging.Logger) -> None: + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + base_url="https://api.schematichq.com", + logger=logger, + )) + key = client._resource_key_to_cache_key("company", "Slug", "AcmeCorp") + assert "slug" in key + assert "acmecorp" in key + + +class TestDataStreamClientFlagEvaluation: + async def test_evaluate_flag_returns_default_when_engine_unavailable(self, logger: logging.Logger) -> None: + from schematic.types import RulesengineFlag + + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + flag = RulesengineFlag( + id="f1", key="test", account_id="a", environment_id="e", + default_value=True, rules=[], + ) + result = client._evaluate_flag(flag, None, None) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.value is True + assert result.reason == "RULES_ENGINE_UNAVAILABLE" + assert result.flag_key == "test" + + async def test_check_flag_raises_when_flag_not_found(self, logger: logging.Logger) -> None: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + with pytest.raises(RuntimeError, match="Flag not found"): + await client.check_flag(CheckFlagRequestBody(), "nonexistent-flag") diff --git a/tests/datastream/test_merge.py b/tests/datastream/test_merge.py new file mode 100644 index 0000000..a456336 --- /dev/null +++ b/tests/datastream/test_merge.py @@ -0,0 +1,542 @@ +from __future__ import annotations + +import datetime as dt + +import pytest + +from schematic.datastream.merge import ( + deep_copy_company, + deep_copy_user, + extract_id, + partial_company, + partial_user, +) +from schematic.types import ( + RulesengineCompany, + RulesengineCompanyMetric, + RulesengineFeatureEntitlement, + RulesengineRule, + RulesengineSubscription, + RulesengineTrait, + RulesengineTraitDefinition, + RulesengineUser, +) + + +def _make_trait(value: str, definition_id: str | None = None) -> RulesengineTrait: + td = None + if definition_id is not None: + td = RulesengineTraitDefinition( + id=definition_id, + comparable_type="string", + entity_type="company", + ) + return RulesengineTrait(value=value, trait_definition=td) + + +def _make_rule(rule_id: str) -> RulesengineRule: + return RulesengineRule( + id=rule_id, + name=rule_id, + priority=1, + value=True, + rule_type="override", + account_id="acc-1", + environment_id="env-1", + condition_groups=[], + conditions=[], + ) + + +def _make_entitlement(feature_id: str, feature_key: str) -> RulesengineFeatureEntitlement: + return RulesengineFeatureEntitlement( + feature_id=feature_id, + feature_key=feature_key, + value_type="boolean", + ) + + +def _make_metric( + event_subtype: str, + period: str = "all_time", + month_reset: str = "first_of_month", + value: int = 0, +) -> RulesengineCompanyMetric: + return RulesengineCompanyMetric( + account_id="acc-1", + company_id="co-1", + created_at=dt.datetime(2026, 1, 1, tzinfo=dt.timezone.utc), + environment_id="env-1", + event_subtype=event_subtype, + month_reset=month_reset, + period=period, + value=value, + ) + + +def base_company() -> RulesengineCompany: + return RulesengineCompany( + id="co-1", + account_id="acc-1", + environment_id="env-1", + base_plan_id="plan-1", + billing_product_ids=["bp-1"], + credit_balances={"credit-1": 100.0}, + keys={"domain": "example.com"}, + plan_ids=["plan-1"], + plan_version_ids=["pv-1"], + traits=[_make_trait("Enterprise", "plan")], + entitlements=[_make_entitlement("feat-1", "feature-one")], + metrics=[], + rules=[], + ) + + +def base_user() -> RulesengineUser: + return RulesengineUser( + id="user-1", + account_id="acc-1", + environment_id="env-1", + keys={"email": "user@example.com"}, + traits=[_make_trait("Premium", "tier")], + rules=[], + ) + + +# ------------------------------------------------------------------ +# partial_company tests +# ------------------------------------------------------------------ + + +class TestPartialCompanyOnlyTraits: + def test_replaces_traits_preserves_other_fields(self) -> None: + existing = base_company() + partial = { + "id": "co-1", + "traits": [{"value": "Startup", "trait_definition": {"id": "plan", "comparable_type": "string", "entity_type": "company"}}], + } + + merged = partial_company(existing, partial) + + assert len(merged.traits) == 1 + assert merged.traits[0].value == "Startup" + + assert merged.account_id == "acc-1" + assert merged.environment_id == "env-1" + assert merged.keys == {"domain": "example.com"} + assert merged.billing_product_ids == ["bp-1"] + assert merged.base_plan_id == "plan-1" + + +class TestPartialCompanyMergesKeys: + def test_new_key_added_existing_preserved(self) -> None: + existing = base_company() + partial = {"id": "co-1", "keys": {"slug": "new-slug"}} + + merged = partial_company(existing, partial) + + assert merged.keys == {"domain": "example.com", "slug": "new-slug"} + assert len(merged.traits) == 1 + + +class TestPartialCompanyMergesCreditBalances: + def test_new_balance_added_existing_preserved(self) -> None: + existing = base_company() + partial = {"id": "co-1", "credit_balances": {"credit-2": 200.0}} + + merged = partial_company(existing, partial) + + assert merged.credit_balances == {"credit-1": 100.0, "credit-2": 200.0} + + def test_overwrites_existing_balance(self) -> None: + existing = base_company() + partial = {"id": "co-1", "credit_balances": {"credit-1": 50.0}} + + merged = partial_company(existing, partial) + + assert merged.credit_balances == {"credit-1": 50.0} + + +class TestPartialCompanyUpsertsMetrics: + def test_updates_matching_appends_new(self) -> None: + existing = base_company().model_copy( + update={ + "metrics": [ + _make_metric("event-a", "all_time", "first_of_month", 10), + _make_metric("event-b", "current_month", "first_of_month", 5), + ], + } + ) + partial = { + "id": "co-1", + "metrics": [ + {"event_subtype": "event-a", "period": "all_time", "month_reset": "first_of_month", "value": 42, + "account_id": "acc-1", "company_id": "co-1", "environment_id": "env-1", + "created_at": "2026-01-01T00:00:00Z"}, + {"event_subtype": "event-c", "period": "current_day", "month_reset": "billing_cycle", "value": 1, + "account_id": "acc-1", "company_id": "co-1", "environment_id": "env-1", + "created_at": "2026-01-01T00:00:00Z"}, + ], + } + + merged = partial_company(existing, partial) + + assert len(merged.metrics) == 3 + # event-a updated in place + assert merged.metrics[0].event_subtype == "event-a" + assert merged.metrics[0].value == 42 + # event-b unchanged + assert merged.metrics[1].event_subtype == "event-b" + assert merged.metrics[1].value == 5 + # event-c appended + assert merged.metrics[2].event_subtype == "event-c" + assert merged.metrics[2].value == 1 + + # Original not mutated + assert existing.metrics[0].value == 10 + + +class TestPartialCompanyEmptyEntitlements: + def test_clears_entitlements(self) -> None: + existing = base_company() + partial = {"id": "co-1", "entitlements": []} + + merged = partial_company(existing, partial) + + assert merged.entitlements == [] + assert merged.account_id == "acc-1" + + +class TestPartialCompanyNullBasePlanID: + def test_sets_base_plan_to_none(self) -> None: + existing = base_company() + partial = {"id": "co-1", "base_plan_id": None} + + merged = partial_company(existing, partial) + + assert merged.base_plan_id is None + assert merged.billing_product_ids == ["bp-1"] + + +class TestPartialCompanyMissingID: + def test_raises_value_error(self) -> None: + existing = base_company() + partial = {"traits": []} + + with pytest.raises(ValueError, match="missing required field: id"): + partial_company(existing, partial) + + +class TestPartialCompanyDoesNotMutateOriginal: + def test_original_unchanged(self) -> None: + existing = base_company() + orig_keys = dict(existing.keys) + + partial = {"id": "co-1", "keys": {"slug": "new-slug"}, "traits": []} + + merged = partial_company(existing, partial) + + assert existing.keys == orig_keys + assert len(existing.traits) == 1 + assert merged.keys == {"domain": "example.com", "slug": "new-slug"} + assert merged.traits == [] + + +class TestPartialCompanyRules: + def test_replaces_rules(self) -> None: + existing = base_company().model_copy(update={"rules": [_make_rule("rule-old")]}) + partial = { + "id": "co-1", + "rules": [{"id": "rule-new", "name": "rule-new", "priority": 1, "value": True, + "rule_type": "override", "account_id": "acc-1", "environment_id": "env-1", + "condition_groups": [], "conditions": []}], + } + + merged = partial_company(existing, partial) + + assert len(merged.rules) == 1 + assert merged.rules[0].id == "rule-new" + assert existing.rules[0].id == "rule-old" + + +class TestPartialCompanyFullEntity: + def test_full_entity_partial_message(self) -> None: + existing = base_company().model_copy( + update={ + "metrics": [_make_metric("event-a", "all_time", "first_of_month", 10)], + "rules": [_make_rule("rule-1")], + } + ) + + partial = { + "id": "co-1", + "account_id": "acc-2", + "environment_id": "env-2", + "base_plan_id": "plan-99", + "billing_product_ids": ["bp-10", "bp-20"], + "credit_balances": {"credit-1": 999.0, "credit-new": 50.0}, + "entitlements": [ + {"feature_id": "feat-new", "feature_key": "feature-new", "value_type": "boolean"}, + {"feature_id": "feat-2", "feature_key": "feature-two", "value_type": "boolean"}, + ], + "keys": {"domain": "new.com", "slug": "new-slug"}, + "metrics": [ + {"event_subtype": "event-a", "period": "all_time", "month_reset": "first_of_month", "value": 42, + "account_id": "acc-1", "company_id": "co-1", "environment_id": "env-1", + "created_at": "2026-01-01T00:00:00Z"}, + {"event_subtype": "event-new", "period": "current_day", "month_reset": "billing_cycle", "value": 7, + "account_id": "acc-1", "company_id": "co-1", "environment_id": "env-1", + "created_at": "2026-01-01T00:00:00Z"}, + ], + "plan_ids": ["plan-99", "plan-100"], + "plan_version_ids": ["pv-99"], + "rules": [ + {"id": "rule-new-1", "name": "r1", "priority": 1, "value": True, "rule_type": "override", + "account_id": "acc-1", "environment_id": "env-1", "condition_groups": [], "conditions": []}, + {"id": "rule-new-2", "name": "r2", "priority": 2, "value": False, "rule_type": "override", + "account_id": "acc-1", "environment_id": "env-1", "condition_groups": [], "conditions": []}, + ], + "subscription": {"id": "sub-new", "period_start": "2026-01-01T00:00:00Z", "period_end": "2026-02-01T00:00:00Z"}, + "traits": [ + {"value": "Startup", "trait_definition": {"id": "tier", "comparable_type": "string", "entity_type": "company"}}, + {"value": "Annual", "trait_definition": {"id": "billing", "comparable_type": "string", "entity_type": "company"}}, + ], + } + + merged = partial_company(existing, partial) + + assert merged.id == "co-1" + assert merged.account_id == "acc-2" + assert merged.environment_id == "env-2" + assert merged.base_plan_id == "plan-99" + assert merged.billing_product_ids == ["bp-10", "bp-20"] + + # Credit balances merge: existing credit-1 overwritten, credit-new added + assert merged.credit_balances == {"credit-1": 999.0, "credit-new": 50.0} + + assert len(merged.entitlements) == 2 + assert merged.entitlements[0].feature_id == "feat-new" + assert merged.entitlements[1].feature_id == "feat-2" + + # Keys merge: domain overwritten, slug added + assert merged.keys == {"domain": "new.com", "slug": "new-slug"} + + # Metrics upsert: event-a updated, event-new appended + assert len(merged.metrics) == 2 + assert merged.metrics[0].event_subtype == "event-a" + assert merged.metrics[0].value == 42 + assert merged.metrics[1].event_subtype == "event-new" + assert merged.metrics[1].value == 7 + + assert merged.plan_ids == ["plan-99", "plan-100"] + assert merged.plan_version_ids == ["pv-99"] + + assert len(merged.rules) == 2 + assert merged.rules[0].id == "rule-new-1" + assert merged.rules[1].id == "rule-new-2" + + assert merged.subscription is not None + assert merged.subscription.id == "sub-new" + + assert len(merged.traits) == 2 + assert merged.traits[0].value == "Startup" + assert merged.traits[1].value == "Annual" + + # Original not mutated + assert existing.account_id == "acc-1" + assert existing.base_plan_id == "plan-1" + assert existing.keys == {"domain": "example.com"} + assert existing.metrics[0].value == 10 + + +# ------------------------------------------------------------------ +# partial_user tests +# ------------------------------------------------------------------ + + +class TestPartialUserOnlyTraits: + def test_replaces_traits_preserves_keys(self) -> None: + existing = base_user() + partial = { + "id": "user-1", + "traits": [{"value": "Free", "trait_definition": {"id": "tier", "comparable_type": "string", "entity_type": "user"}}], + } + + merged = partial_user(existing, partial) + + assert len(merged.traits) == 1 + assert merged.traits[0].value == "Free" + assert merged.keys == {"email": "user@example.com"} + + +class TestPartialUserMergesKeys: + def test_new_key_added_existing_preserved(self) -> None: + existing = base_user() + partial = {"id": "user-1", "keys": {"slack_id": "U123"}} + + merged = partial_user(existing, partial) + + assert merged.keys == {"email": "user@example.com", "slack_id": "U123"} + assert len(merged.traits) == 1 + + +class TestPartialUserMissingID: + def test_raises_value_error(self) -> None: + existing = base_user() + partial = {"keys": {"email": "new@example.com"}} + + with pytest.raises(ValueError, match="missing required field: id"): + partial_user(existing, partial) + + +class TestPartialUserDoesNotMutateOriginal: + def test_original_unchanged(self) -> None: + existing = base_user() + orig_keys = dict(existing.keys) + + partial = {"id": "user-1", "keys": {"slug": "new"}, "traits": []} + + merged = partial_user(existing, partial) + + assert existing.keys == orig_keys + assert len(existing.traits) == 1 + assert merged.keys == {"email": "user@example.com", "slug": "new"} + assert merged.traits == [] + + +class TestPartialUserFullEntity: + def test_full_entity_partial_message(self) -> None: + existing = base_user().model_copy(update={"rules": [_make_rule("rule-1")]}) + + partial = { + "id": "user-1", + "account_id": "acc-2", + "environment_id": "env-2", + "keys": {"email": "new@example.com", "slack_id": "U999"}, + "traits": [ + {"value": "Free", "trait_definition": {"id": "tier", "comparable_type": "string", "entity_type": "user"}}, + {"value": "Monthly", "trait_definition": {"id": "billing", "comparable_type": "string", "entity_type": "user"}}, + ], + "rules": [ + {"id": "rule-new-1", "name": "r1", "priority": 1, "value": True, "rule_type": "override", + "account_id": "acc-1", "environment_id": "env-1", "condition_groups": [], "conditions": []}, + {"id": "rule-new-2", "name": "r2", "priority": 2, "value": False, "rule_type": "override", + "account_id": "acc-1", "environment_id": "env-1", "condition_groups": [], "conditions": []}, + ], + } + + merged = partial_user(existing, partial) + + assert merged.id == "user-1" + assert merged.account_id == "acc-2" + assert merged.environment_id == "env-2" + + # Keys merge: email overwritten, slack_id added + assert merged.keys == {"email": "new@example.com", "slack_id": "U999"} + + assert len(merged.traits) == 2 + assert merged.traits[0].value == "Free" + assert merged.traits[1].value == "Monthly" + + assert len(merged.rules) == 2 + assert merged.rules[0].id == "rule-new-1" + assert merged.rules[1].id == "rule-new-2" + + # Original not mutated + assert existing.account_id == "acc-1" + assert existing.keys == {"email": "user@example.com"} + assert len(existing.traits) == 1 + assert existing.rules[0].id == "rule-1" + + +# ------------------------------------------------------------------ +# extract_id tests +# ------------------------------------------------------------------ + + +class TestExtractID: + def test_from_dict(self) -> None: + assert extract_id({"id": "co-1", "traits": []}) == "co-1" + + def test_from_model(self) -> None: + user = base_user() + assert extract_id(user) == "user-1" + + def test_missing_returns_none(self) -> None: + assert extract_id({"traits": []}) is None + + def test_none_returns_none(self) -> None: + assert extract_id(None) is None + + +# ------------------------------------------------------------------ +# deep_copy tests +# ------------------------------------------------------------------ + + +class TestDeepCopyCompany: + def test_none_returns_none(self) -> None: + assert deep_copy_company(None) is None + + def test_full_copy_is_independent(self) -> None: + orig = base_company().model_copy( + update={ + "subscription": RulesengineSubscription( + id="sub-1", + period_start=dt.datetime(2026, 1, 1, tzinfo=dt.timezone.utc), + period_end=dt.datetime(2026, 2, 1, tzinfo=dt.timezone.utc), + ), + "metrics": [ + _make_metric("event-1", value=42), + ], + } + ) + + cp = deep_copy_company(orig) + + assert cp.id == orig.id + assert cp.account_id == orig.account_id + assert cp.environment_id == orig.environment_id + assert cp.base_plan_id == orig.base_plan_id + assert cp.keys == orig.keys + assert cp.credit_balances == orig.credit_balances + assert cp.subscription.id == "sub-1" + assert cp.metrics[0].value == 42 + + # Verify it's a separate object + assert cp is not orig + + +class TestDeepCopyUser: + def test_empty_fields(self) -> None: + orig = RulesengineUser( + id="u1", + account_id="acc-1", + environment_id="env-1", + keys={}, + traits=[], + rules=[], + ) + cp = deep_copy_user(orig) + + assert cp.id == "u1" + assert cp.keys == {} + assert cp.traits == [] + assert cp.rules == [] + + def test_full_copy_is_independent(self) -> None: + orig = base_user().model_copy(update={"rules": [_make_rule("r1")]}) + + cp = deep_copy_user(orig) + + assert cp.id == orig.id + assert cp.account_id == orig.account_id + assert cp.keys == orig.keys + assert cp.traits[0].value == "Premium" + assert cp.rules[0].id == "r1" + + # Verify it's a separate object + assert cp is not orig + + def test_none_returns_none(self) -> None: + assert deep_copy_user(None) is None diff --git a/tests/datastream/test_rules_engine.py b/tests/datastream/test_rules_engine.py new file mode 100644 index 0000000..901a036 --- /dev/null +++ b/tests/datastream/test_rules_engine.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +import pytest + +from schematic.datastream.rules_engine import RulesEngineClient +from schematic.types import RulesengineCheckFlagResult, RulesengineFlag, RulesengineRule + +# Skip all tests if wasmtime is not installed +wasmtime = pytest.importorskip("wasmtime", reason="wasmtime not installed") + + +def _make_flag(**overrides: object) -> RulesengineFlag: + """Build a minimal valid flag for the WASM rules engine.""" + defaults = dict( + id="flag1", + key="test-flag", + account_id="acc_1", + environment_id="env_1", + default_value=False, + rules=[], + ) + defaults.update(overrides) + return RulesengineFlag(**defaults) # type: ignore[arg-type] + + + +class TestRulesEngineClientInit: + async def test_initialize_loads_wasm(self) -> None: + engine = RulesEngineClient() + assert not engine.is_initialized() + await engine.initialize() + assert engine.is_initialized() + + async def test_initialize_is_idempotent(self) -> None: + engine = RulesEngineClient() + await engine.initialize() + await engine.initialize() # Should not raise + assert engine.is_initialized() + + async def test_get_version_key(self) -> None: + engine = RulesEngineClient() + await engine.initialize() + version = engine.get_version_key() + assert isinstance(version, str) + assert len(version) == 8 # 8-char hex string + + def test_check_flag_before_init_raises(self) -> None: + engine = RulesEngineClient() + with pytest.raises(RuntimeError, match="not initialized"): + engine.check_flag(_make_flag()) + + +class TestRulesEngineCheckFlag: + @pytest.fixture + async def engine(self) -> RulesEngineClient: + e = RulesEngineClient() + await e.initialize() + return e + + async def test_evaluates_flag_with_default_value(self, engine: RulesEngineClient) -> None: + flag = _make_flag(default_value=True) + result = engine.check_flag(flag) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.value is True + + async def test_evaluates_flag_with_company_context(self, engine: RulesEngineClient) -> None: + from schematic.types import RulesengineCompany + + flag = _make_flag( + default_value=False, + rules=[ + RulesengineRule( + id="rule1", + account_id="acc_1", + environment_id="env_1", + name="Global Override", + rule_type="global_override", + value=True, + priority=1, + conditions=[], + condition_groups=[], + ) + ], + ) + company = RulesengineCompany( + id="co_123", + account_id="acc_1", + environment_id="env_1", + keys={"id": "co_123"}, + traits=[], + metrics=[], + rules=[], + entitlements=[], + billing_product_ids=[], + credit_balances={}, + plan_ids=[], + plan_version_ids=[], + ) + result = engine.check_flag(flag, company) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.value is True + assert result.reason != "" + + async def test_evaluates_flag_with_user_context(self, engine: RulesEngineClient) -> None: + from schematic.types import RulesengineUser + + flag = _make_flag(id="flag2", key="user-flag", default_value=True) + user = RulesengineUser( + id="usr_456", + account_id="acc_1", + environment_id="env_1", + keys={"id": "usr_456"}, + traits=[], + rules=[], + ) + result = engine.check_flag(flag, None, user) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.value is True + + async def test_returns_default_for_empty_rules(self, engine: RulesEngineClient) -> None: + flag = _make_flag(id="flag3", key="empty-rules", default_value=False) + result = engine.check_flag(flag) + assert result.value is False + + +class TestRulesEngineFileNotFound: + async def test_missing_wasm_raises(self) -> None: + engine = RulesEngineClient(wasm_path="/nonexistent/rulesengine.wasm") + with pytest.raises(FileNotFoundError): + await engine.initialize() From fd3fae4315bff22707dd18b2fc26908d999a25f6 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 12:10:39 -0600 Subject: [PATCH 04/19] add better test coverage --- src/schematic/client.py | 14 +- tests/custom/test_cache.py | 218 +++++++++++++ tests/custom/test_cache_key.py | 69 +++++ tests/custom/test_client.py | 495 +++++++++++++++++++++++++++++- tests/custom/test_event_buffer.py | 106 +++++++ 5 files changed, 895 insertions(+), 7 deletions(-) create mode 100644 tests/custom/test_cache_key.py diff --git a/src/schematic/client.py b/src/schematic/client.py index 5b09c95..44c45e3 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -79,9 +79,10 @@ def __init__(self, api_key: str, config: Optional[SchematicConfig] = None): logger=self.logger, period=self.event_buffer_period, ) - self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = config.cache_providers or [ - LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) - ] + self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = ( + config.cache_providers if config.cache_providers is not None + else [LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL)] + ) self.offline = config.offline atexit.register(self.shutdown) @@ -277,9 +278,10 @@ def __init__(self, api_key: str, config: Optional[AsyncSchematicConfig] = None): logger=self.logger, period=self.event_buffer_period, ) - self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = config.cache_providers or [ - LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL) - ] + self.flag_check_cache_providers: List[CacheProvider[CheckFlagResponseData]] = ( + config.cache_providers if config.cache_providers is not None + else [LocalCache[CheckFlagResponseData](DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL)] + ) self.offline = config.offline self._shutdown_requested = False self._is_shutting_down = False diff --git a/tests/custom/test_cache.py b/tests/custom/test_cache.py index 5f7ba7e..3cd5c8f 100644 --- a/tests/custom/test_cache.py +++ b/tests/custom/test_cache.py @@ -1,3 +1,5 @@ +import time +import threading import unittest from schematic.cache import LocalCache @@ -27,5 +29,221 @@ def test_cache_size_limit(self): self.assertEqual(val3, "value3") +class TestLocalCacheGetSet(unittest.TestCase): + """Corresponds to Go TestLocalCache_Get_Set.""" + + def test_basic_set_and_get(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key1", "value1") + self.assertEqual(cache.get("key1"), "value1") + + def test_get_nonexistent_key(self): + cache = LocalCache(max_size=10, ttl=5000) + self.assertIsNone(cache.get("missing")) + + def test_overwrite_existing_key(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key1", "value1") + cache.set("key1", "value2") + self.assertEqual(cache.get("key1"), "value2") + + def test_set_with_custom_ttl(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key1", "value1", ttl_override=1) # 1ms TTL + time.sleep(0.05) + self.assertIsNone(cache.get("key1")) + + +class TestLocalCacheDelete(unittest.TestCase): + """Corresponds to Go TestLocalCache_Delete.""" + + def test_delete_existing_key(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key1", "value1") + cache.set("key2", "value2") + # Remove key1 by overwriting the cache internals + del cache.cache["key1"] + self.assertIsNone(cache.get("key1")) + self.assertEqual(cache.get("key2"), "value2") + + def test_delete_nonexistent_key(self): + """Deleting a nonexistent key should not raise.""" + cache = LocalCache(max_size=10, ttl=5000) + # Accessing a missing key via cache internals should not error + cache.cache.pop("missing", None) + + +class TestLocalCacheLRU(unittest.TestCase): + """Corresponds to Go TestLocalCache_LRU.""" + + def test_lru_eviction(self): + cache = LocalCache(max_size=3, ttl=5000) + cache.set("key1", "value1") + cache.set("key2", "value2") + cache.set("key3", "value3") + + # Access key1 to make it most recently used + cache.get("key1") + + # Adding key4 should evict key2 (least recently used) + cache.set("key4", "value4") + + self.assertEqual(cache.get("key1"), "value1") + self.assertIsNone(cache.get("key2")) + self.assertEqual(cache.get("key3"), "value3") + self.assertEqual(cache.get("key4"), "value4") + + +class TestLocalCacheExpiration(unittest.TestCase): + """Corresponds to Go TestLocalCache_Expiration.""" + + def test_items_expire_after_ttl(self): + cache = LocalCache(max_size=10, ttl=50) # 50ms TTL + cache.set("key1", "value1") + + # Immediately available + self.assertEqual(cache.get("key1"), "value1") + + # Gone after TTL + time.sleep(0.1) + self.assertIsNone(cache.get("key1")) + + def test_new_items_work_after_expiration(self): + cache = LocalCache(max_size=10, ttl=50) + cache.set("key1", "value1") + time.sleep(0.1) + self.assertIsNone(cache.get("key1")) + + # New items should still work + cache.set("key2", "value2") + self.assertEqual(cache.get("key2"), "value2") + + +class TestLocalCacheCleanExpired(unittest.TestCase): + """Corresponds to Go TestLocalCache_CleanupRoutine.""" + + def test_clean_expired_removes_stale_items(self): + cache = LocalCache(max_size=10, ttl=50) + for i in range(5): + cache.set(f"key{i}", f"value{i}") + + time.sleep(0.1) + cache.clean_expired() + + for i in range(5): + self.assertIsNone(cache.get(f"key{i}")) + + def test_clean_expired_keeps_valid_items(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key1", "value1") + cache.clean_expired() + self.assertEqual(cache.get("key1"), "value1") + + +class TestLocalCacheZeroSize(unittest.TestCase): + """Corresponds to Go TestLocalCache_NilSafety (zero-size cache acts as disabled).""" + + def test_get_returns_none(self): + cache = LocalCache(max_size=0, ttl=5000) + self.assertIsNone(cache.get("key1")) + + def test_set_is_noop(self): + cache = LocalCache(max_size=0, ttl=5000) + cache.set("key1", "value1") + self.assertIsNone(cache.get("key1")) + + +class TestLocalCacheDefaults(unittest.TestCase): + """Corresponds to Go TestLocalCache_DefaultCache.""" + + def test_default_cache_has_correct_defaults(self): + from schematic.cache.local import DEFAULT_CACHE_SIZE, DEFAULT_CACHE_TTL + cache = LocalCache() + self.assertEqual(cache.max_size, DEFAULT_CACHE_SIZE) + self.assertEqual(cache.ttl, DEFAULT_CACHE_TTL) + + +class TestLocalCacheDifferentTypes(unittest.TestCase): + """Corresponds to Go TestLocalCache_DifferentTypes.""" + + def test_string_cache(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key", "hello") + self.assertEqual(cache.get("key"), "hello") + + def test_int_cache(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key", 42) + self.assertEqual(cache.get("key"), 42) + + def test_dict_cache(self): + cache = LocalCache(max_size=10, ttl=5000) + val = {"name": "test", "items": [1, 2, 3]} + cache.set("key", val) + self.assertEqual(cache.get("key"), val) + + +class TestLocalCacheConcurrency(unittest.TestCase): + """Corresponds to Go TestLocalCache_Concurrency and TestLocalCache_ConcurrentSafe.""" + + def test_concurrent_reads_and_writes(self): + cache = LocalCache(max_size=100, ttl=5000) + errors = [] + + def worker(worker_id): + try: + for i in range(20): + key = f"key-{worker_id}-{i}" + cache.set(key, f"value-{i}") + cache.get(key) + cache.get(f"key-{(worker_id + 1) % 5}-{i}") + except Exception as e: + errors.append(e) + + threads = [threading.Thread(target=worker, args=(i,)) for i in range(5)] + for t in threads: + t.start() + for t in threads: + t.join() + + self.assertEqual(len(errors), 0, f"Concurrent access errors: {errors}") + + +class TestLocalCacheEdgeCases(unittest.TestCase): + """Corresponds to Go TestLocalCache_EdgeCases.""" + + def test_very_short_ttl(self): + cache = LocalCache(max_size=10, ttl=1) # 1ms + cache.set("key", "value") + time.sleep(0.01) + self.assertIsNone(cache.get("key")) + + def test_very_large_ttl(self): + cache = LocalCache(max_size=10, ttl=100 * 365 * 24 * 60 * 60 * 1000) # 100 years + cache.set("key", "value") + self.assertEqual(cache.get("key"), "value") + + def test_zero_ttl(self): + """Zero TTL means items expire immediately.""" + cache = LocalCache(max_size=10, ttl=0) + cache.set("key", "value") + # With 0 TTL, expiration = now, so item is already expired + self.assertIsNone(cache.get("key")) + + def test_ttl_override_shorter_than_default(self): + cache = LocalCache(max_size=10, ttl=5000) + cache.set("key", "value", ttl_override=1) # 1ms override + time.sleep(0.05) + self.assertIsNone(cache.get("key")) + + def test_max_size_enforcement(self): + cache = LocalCache(max_size=3, ttl=5000) + for i in range(10): + cache.set(f"key{i}", f"value{i}") + # Only the last 3 should remain + count = sum(1 for i in range(10) if cache.get(f"key{i}") is not None) + self.assertEqual(count, 3) + + if __name__ == "__main__": unittest.main() diff --git a/tests/custom/test_cache_key.py b/tests/custom/test_cache_key.py new file mode 100644 index 0000000..b933862 --- /dev/null +++ b/tests/custom/test_cache_key.py @@ -0,0 +1,69 @@ +"""Tests for flag check cache key generation. + +Corresponds to Go flags/flags_test.go TestFlagCheckCacheKey. +""" + +import unittest + +from schematic.client import _build_cache_key + + +class TestBuildCacheKey(unittest.TestCase): + """Corresponds to Go TestFlagCheckCacheKey.""" + + def test_empty_context_and_flag_key(self): + result = _build_cache_key("") + self.assertEqual(result, "") + + def test_flag_key_only(self): + result = _build_cache_key("feature_flag_1") + self.assertEqual(result, "feature_flag_1") + + def test_with_company_and_user(self): + result = _build_cache_key( + "feature_flag_1", + company={"id": "123", "name": "ACME Inc."}, + user={"id": "456", "email": "john@example.com"}, + ) + # Should include flag key, company, and user in the cache key + self.assertIn("feature_flag_1", result) + self.assertIn("123", result) + self.assertIn("ACME Inc.", result) + self.assertIn("456", result) + self.assertIn("john@example.com", result) + + def test_with_company_only(self): + result = _build_cache_key( + "feature_flag_2", + company={"id": "789", "name": "XYZ Corp."}, + ) + self.assertIn("feature_flag_2", result) + self.assertIn("789", result) + self.assertIn("XYZ Corp.", result) + + def test_with_user_only(self): + result = _build_cache_key( + "feature_flag_3", + user={"id": "abc", "email": "jane@example.com"}, + ) + self.assertIn("feature_flag_3", result) + self.assertIn("abc", result) + self.assertIn("jane@example.com", result) + + def test_different_contexts_produce_different_keys(self): + """Different company/user contexts should produce different cache keys.""" + key1 = _build_cache_key("flag", company={"id": "comp-1"}) + key2 = _build_cache_key("flag", company={"id": "comp-2"}) + key3 = _build_cache_key("flag", user={"id": "user-1"}) + self.assertNotEqual(key1, key2) + self.assertNotEqual(key1, key3) + + def test_same_context_produces_same_key(self): + """Same inputs should always produce the same cache key.""" + key1 = _build_cache_key("flag", company={"id": "comp-1"}, user={"id": "user-1"}) + key2 = _build_cache_key("flag", company={"id": "comp-1"}, user={"id": "user-1"}) + self.assertEqual(key1, key2) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/custom/test_client.py b/tests/custom/test_client.py index ebd503e..e646693 100644 --- a/tests/custom/test_client.py +++ b/tests/custom/test_client.py @@ -1,9 +1,11 @@ +import time import unittest from unittest.mock import AsyncMock, MagicMock, patch import pytest from httpx import AsyncClient, Client +from schematic.cache import LocalCache from schematic.client import ( AsyncSchematic, AsyncSchematicConfig, @@ -11,7 +13,7 @@ Schematic, SchematicConfig, ) -from schematic.types import CheckFlagResponseData +from schematic.types import CheckFlagResponseData, FeatureEntitlement class TestSchematic(unittest.TestCase): @@ -155,6 +157,252 @@ def test_track_with_quantity(self): ) mock_push.assert_called_once() + def test_check_flag_with_no_cache(self): + """Verify that when cache_providers is empty, every call hits the API.""" + config = SchematicConfig( + event_buffer_period=1, + logger=MagicMock(), + httpx_client=MagicMock(spec=Client), + cache_providers=[], + ) + client = Schematic("api_key", config) + try: + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + client.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + + result1 = client.check_flag("test_flag") + result2 = client.check_flag("test_flag") + self.assertTrue(result1) + self.assertTrue(result2) + self.assertEqual(client.features.check_flag.call_count, 2) + finally: + client.event_buffer.stop() + + def test_check_flag_with_cache_ttl_expiry(self): + """Verify cache expires after TTL.""" + short_ttl_cache = LocalCache(max_size=1000, ttl=50) # 50ms TTL + config = SchematicConfig( + event_buffer_period=1, + logger=MagicMock(), + httpx_client=MagicMock(spec=Client), + cache_providers=[short_ttl_cache], + ) + client = Schematic("api_key", config) + try: + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + client.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + + # First call hits API and caches + self.assertTrue(client.check_flag("test_flag")) + # Second call should hit cache + self.assertTrue(client.check_flag("test_flag")) + self.assertEqual(client.features.check_flag.call_count, 1) + + # Wait for TTL to expire + time.sleep(0.1) + + # Third call should miss cache and hit API again + self.assertTrue(client.check_flag("test_flag")) + self.assertEqual(client.features.check_flag.call_count, 2) + finally: + client.event_buffer.stop() + + def test_check_flag_returns_default_on_api_error(self): + """Verify that API errors return the flag default value.""" + self.schematic.flag_defaults = {"test_flag": True} + self.schematic.flag_check_cache_providers = [] + self.schematic.features.check_flag = MagicMock( + side_effect=Exception("api error") + ) + result = self.schematic.check_flag("test_flag") + self.assertTrue(result) + + def test_check_flag_returns_false_on_error_no_default(self): + """Verify that API errors with no default return False.""" + self.schematic.flag_check_cache_providers = [] + self.schematic.features.check_flag = MagicMock( + side_effect=Exception("connection refused") + ) + result = self.schematic.check_flag("test_flag") + self.assertFalse(result) + + def test_check_flag_offline_no_default(self): + """Verify that offline mode with no default returns False.""" + self.schematic.offline = True + result = self.schematic.check_flag("test_flag") + self.assertFalse(result) + + def test_check_flag_with_company_context_only(self): + """Verify flag check passes company context correctly.""" + self.schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag( + "test_flag", + company={"company-id": "comp-123"}, + ) + self.assertTrue(result) + call_kwargs = self.schematic.features.check_flag.call_args + self.assertEqual(call_kwargs.kwargs["company"], {"company-id": "comp-123"}) + self.assertIsNone(call_kwargs.kwargs["user"]) + + def test_check_flag_with_user_context_only(self): + """Verify flag check passes user context correctly.""" + self.schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag( + "test_flag", + user={"user-id": "user-123"}, + ) + self.assertTrue(result) + call_kwargs = self.schematic.features.check_flag.call_args + self.assertIsNone(call_kwargs.kwargs["company"]) + self.assertEqual(call_kwargs.kwargs["user"], {"user-id": "user-123"}) + + def test_check_flag_with_both_contexts(self): + """Verify flag check passes both company and user context.""" + self.schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag( + "test_flag", + company={"company-id": "comp-123"}, + user={"user-id": "user-123"}, + ) + self.assertTrue(result) + call_kwargs = self.schematic.features.check_flag.call_args + self.assertEqual(call_kwargs.kwargs["company"], {"company-id": "comp-123"}) + self.assertEqual(call_kwargs.kwargs["user"], {"user-id": "user-123"}) + + def test_check_flag_with_entitlement_nil_entitlement(self): + """Verify handling of API response with no entitlement.""" + self.schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=False, + flag="test_flag", + reason="no matching rules", + entitlement=None, + rule_type=None, + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag_with_entitlement("test_flag") + self.assertIsInstance(result, CheckFlagResponseData) + self.assertFalse(result.value) + self.assertIsNone(result.entitlement) + self.assertIsNone(result.rule_type) + + def test_check_flag_with_entitlement_cache_preserves_entitlement(self): + """Verify cache hit preserves full entitlement data.""" + entitlement = FeatureEntitlement( + feature_id="feat-123", + feature_key="test-feature", + value_type="numeric", + allocation=100, + usage=50, + ) + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="entitlement matched", + company_id="comp-123", + flag_id="flag-456", + rule_id="rule-789", + rule_type="plan_entitlement", + user_id="user-321", + entitlement=entitlement, + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + + # First call hits API + result1 = self.schematic.check_flag_with_entitlement("test_flag") + self.assertTrue(result1.value) + self.assertIsNotNone(result1.entitlement) + self.assertEqual(result1.entitlement.feature_id, "feat-123") + + # Second call should hit cache and preserve entitlement + result2 = self.schematic.check_flag_with_entitlement("test_flag") + self.assertTrue(result2.value) + self.assertEqual(result2.reason, "entitlement matched") + self.assertEqual(result2.company_id, "comp-123") + self.assertEqual(result2.flag_id, "flag-456") + self.assertEqual(result2.rule_id, "rule-789") + self.assertEqual(result2.rule_type, "plan_entitlement") + self.assertEqual(result2.user_id, "user-321") + self.assertIsNotNone(result2.entitlement) + self.assertEqual(result2.entitlement.feature_id, "feat-123") + self.assertEqual(result2.entitlement.feature_key, "test-feature") + self.assertEqual(result2.entitlement.allocation, 100) + + # API should only have been called once + self.schematic.features.check_flag.assert_called_once() + + def test_check_flag_with_entitlement_reason_strings(self): + """Corresponds to Go TestCheckFlagWithEntitlement_ReasonStrings. + + Verify that reason, rule_type, and other string fields are preserved. + """ + self.schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + company_id="comp-123", + flag_id="flag-456", + rule_id="rule-789", + rule_type="override", + entitlement=None, + ) + self.schematic.features.check_flag = MagicMock( + return_value=MagicMock(data=mock_data) + ) + result = self.schematic.check_flag_with_entitlement( + "test_flag", + company={"company-id": "comp-123"}, + ) + self.assertIsInstance(result, CheckFlagResponseData) + self.assertTrue(result.value) + self.assertEqual(result.reason, "match") + self.assertEqual(result.company_id, "comp-123") + self.assertEqual(result.flag_id, "flag-456") + self.assertEqual(result.rule_id, "rule-789") + self.assertEqual(result.rule_type, "override") + self.assertIsNone(result.entitlement) + def tearDown(self): self.schematic.event_buffer.stop() @@ -257,6 +505,251 @@ async def test_track(self): ) mock_push.assert_called_once() + async def test_check_flag_with_no_cache(self): + """Verify that when cache_providers is empty, every call hits the API.""" + config = AsyncSchematicConfig( + event_buffer_period=1, + logger=MagicMock(), + httpx_client=MagicMock(spec=AsyncClient), + cache_providers=[], + ) + client = AsyncSchematic("test_key", config) + try: + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + client.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + + result1 = await client.check_flag("test_flag") + result2 = await client.check_flag("test_flag") + assert result1 is True + assert result2 is True + assert client.features.check_flag.call_count == 2 + finally: + await client.event_buffer.stop() + + async def test_check_flag_returns_default_on_api_error(self): + """Verify that API errors return the flag default value.""" + self.async_schematic.flag_defaults = {"test_flag": True} + self.async_schematic.flag_check_cache_providers = [] + self.async_schematic.features.check_flag = AsyncMock( + side_effect=Exception("api error") + ) + result = await self.async_schematic.check_flag("test_flag") + assert result is True + + async def test_check_flag_returns_false_on_error_no_default(self): + """Verify that API errors with no default return False.""" + self.async_schematic.flag_check_cache_providers = [] + self.async_schematic.features.check_flag = AsyncMock( + side_effect=Exception("connection refused") + ) + result = await self.async_schematic.check_flag("test_flag") + assert result is False + + async def test_check_flag_offline_no_default(self): + """Verify that offline mode with no default returns False.""" + self.async_schematic.offline = True + result = await self.async_schematic.check_flag("test_flag") + assert result is False + + async def test_check_flag_with_company_context_only(self): + """Verify flag check passes company context correctly.""" + self.async_schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag( + "test_flag", + company={"company-id": "comp-123"}, + ) + assert result is True + call_kwargs = self.async_schematic.features.check_flag.call_args + assert call_kwargs.kwargs["company"] == {"company-id": "comp-123"} + assert call_kwargs.kwargs["user"] is None + + async def test_check_flag_with_user_context_only(self): + """Verify flag check passes user context correctly.""" + self.async_schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag( + "test_flag", + user={"user-id": "user-123"}, + ) + assert result is True + call_kwargs = self.async_schematic.features.check_flag.call_args + assert call_kwargs.kwargs["company"] is None + assert call_kwargs.kwargs["user"] == {"user-id": "user-123"} + + async def test_check_flag_with_both_contexts(self): + """Verify flag check passes both company and user context.""" + self.async_schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag( + "test_flag", + company={"company-id": "comp-123"}, + user={"user-id": "user-123"}, + ) + assert result is True + call_kwargs = self.async_schematic.features.check_flag.call_args + assert call_kwargs.kwargs["company"] == {"company-id": "comp-123"} + assert call_kwargs.kwargs["user"] == {"user-id": "user-123"} + + async def test_check_flag_with_entitlement_nil_entitlement(self): + """Verify handling of API response with no entitlement.""" + self.async_schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=False, + flag="test_flag", + reason="no matching rules", + entitlement=None, + rule_type=None, + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag_with_entitlement("test_flag") + assert isinstance(result, CheckFlagResponseData) + assert result.value is False + assert result.entitlement is None + assert result.rule_type is None + + async def test_check_flag_with_entitlement_cache_preserves_entitlement(self): + """Verify cache hit preserves full entitlement data.""" + entitlement = FeatureEntitlement( + feature_id="feat-123", + feature_key="test-feature", + value_type="numeric", + allocation=100, + usage=50, + ) + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="entitlement matched", + company_id="comp-123", + flag_id="flag-456", + rule_id="rule-789", + rule_type="plan_entitlement", + user_id="user-321", + entitlement=entitlement, + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + + # First call hits API + result1 = await self.async_schematic.check_flag_with_entitlement("test_flag") + assert result1.value is True + assert result1.entitlement is not None + assert result1.entitlement.feature_id == "feat-123" + + # Second call should hit cache and preserve entitlement + result2 = await self.async_schematic.check_flag_with_entitlement("test_flag") + assert result2.value is True + assert result2.reason == "entitlement matched" + assert result2.company_id == "comp-123" + assert result2.flag_id == "flag-456" + assert result2.rule_id == "rule-789" + assert result2.rule_type == "plan_entitlement" + assert result2.user_id == "user-321" + assert result2.entitlement is not None + assert result2.entitlement.feature_id == "feat-123" + assert result2.entitlement.feature_key == "test-feature" + assert result2.entitlement.allocation == 100 + + # API should only have been called once + self.async_schematic.features.check_flag.assert_called_once() + + async def test_check_flag_with_entitlement_reason_strings(self): + """Corresponds to Go TestCheckFlagWithEntitlement_ReasonStrings (async).""" + self.async_schematic.flag_check_cache_providers = [] + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + company_id="comp-123", + flag_id="flag-456", + rule_id="rule-789", + rule_type="override", + entitlement=None, + ) + self.async_schematic.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + result = await self.async_schematic.check_flag_with_entitlement( + "test_flag", + company={"company-id": "comp-123"}, + ) + assert isinstance(result, CheckFlagResponseData) + assert result.value is True + assert result.reason == "match" + assert result.company_id == "comp-123" + assert result.flag_id == "flag-456" + assert result.rule_id == "rule-789" + assert result.rule_type == "override" + assert result.entitlement is None + + async def test_check_flag_datastream_fallback_to_api(self): + """Corresponds to Go TestCheckFlagDatastreamFallbackToAPI. + + When datastream is configured but fails, should fall back to API. + """ + config = AsyncSchematicConfig( + logger=MagicMock(), + httpx_client=MagicMock(spec=AsyncClient), + event_buffer_period=1, + use_datastream=True, + ) + client = AsyncSchematic("test_key", config) + try: + # Mock the datastream client to raise an error + mock_ds = MagicMock() + mock_ds.check_flag = AsyncMock(side_effect=Exception("datastream failed")) + client._datastream_client = mock_ds + + # Mock the API to return a valid response + mock_data = CheckFlagResponseData( + value=True, + flag="test_flag", + reason="match", + ) + client.features.check_flag = AsyncMock( + return_value=MagicMock(data=mock_data) + ) + client.flag_check_cache_providers = [] + + result = await client.check_flag("test_flag", company={"id": "test-company"}) + assert result is True + + # API should have been called as fallback + client.features.check_flag.assert_called_once() + finally: + await client.event_buffer.stop() + if __name__ == "__main__": unittest.main() diff --git a/tests/custom/test_event_buffer.py b/tests/custom/test_event_buffer.py index bd71ff2..6dffd1a 100644 --- a/tests/custom/test_event_buffer.py +++ b/tests/custom/test_event_buffer.py @@ -1,3 +1,5 @@ +import threading +import time import unittest from unittest.mock import MagicMock, patch, call @@ -52,6 +54,81 @@ def test_stop(self): self.event_buffer.stop() self.assertTrue(self.event_buffer.shutdown.is_set()) + def test_shutdown_flushes_remaining(self): + """Corresponds to Go TestEventBuffer_ShutdownFlushesRemaining. + + Verify that stop() flushes buffered events even if batch isn't full. + """ + mock_api = MagicMock() + mock_logger = MagicMock() + buffer = EventBuffer( + events_api=mock_api, + logger=mock_logger, + period=10, # Long period so periodic flush won't trigger + max_events=100, # Large batch so auto-flush won't trigger + ) + + # Push several events (fewer than max_events so no auto-flush) + for i in range(5): + event = MagicMock(spec=CreateEventRequestBody) + buffer.push(event) + + # No flush should have happened yet + mock_api.create_event_batch.assert_not_called() + + # Stop the buffer, which should flush remaining events + buffer.stop() + + # Verify all events were flushed + mock_api.create_event_batch.assert_called_once() + flushed_events = mock_api.create_event_batch.call_args.kwargs["events"] + self.assertEqual(len(flushed_events), 5) + + def test_concurrent_push(self): + """Corresponds to Go TestEventBuffer_ConcurrentPush. + + Verify no events are lost when pushing from multiple threads. + """ + mock_api = MagicMock() + mock_logger = MagicMock() + buffer = EventBuffer( + events_api=mock_api, + logger=mock_logger, + period=10, # Long period to avoid periodic flush during test + max_events=1000, # Large batch to avoid auto-flush + ) + + num_threads = 10 + events_per_thread = 20 + total_expected = num_threads * events_per_thread + errors = [] + + def worker(): + try: + for _ in range(events_per_thread): + event = MagicMock(spec=CreateEventRequestBody) + buffer.push(event) + except Exception as e: + errors.append(e) + + threads = [threading.Thread(target=worker) for _ in range(num_threads)] + for t in threads: + t.start() + for t in threads: + t.join() + + self.assertEqual(len(errors), 0, f"Concurrent push errors: {errors}") + + # Stop to flush remaining events + buffer.stop() + + # Count total events sent + total_sent = sum( + len(c.kwargs["events"]) + for c in mock_api.create_event_batch.call_args_list + ) + self.assertEqual(total_sent, total_expected) + @pytest.mark.asyncio class TestAsyncEventBuffer: @@ -157,6 +234,35 @@ async def test_stop(self): assert buffer.shutdown_event.is_set() assert buffer.stopped is True + async def test_shutdown_flushes_remaining(self): + """Corresponds to Go TestEventBuffer_ShutdownFlushesRemaining (async).""" + mock_api = MagicMock() + mock_logger = MagicMock() + task_mock = MagicMock() + + with patch('asyncio.create_task', return_value=task_mock): + buffer = AsyncEventBuffer( + events_api=mock_api, + logger=mock_logger, + period=10, + max_events=100, + max_retries=0, + ) + + # Push events (fewer than max_events) + for _ in range(5): + event = MagicMock(spec=CreateEventRequestBody) + await buffer.push(event) + + mock_api.create_event_batch.assert_not_called() + + # Stop should flush remaining events + await buffer.stop() + + mock_api.create_event_batch.assert_called_once() + flushed = mock_api.create_event_batch.call_args.kwargs["events"] + assert len(flushed) == 5 + if __name__ == "__main__": unittest.main() From 490d452ab889c3b1ede8d8e6abb3c77d8a35b577 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 12:59:28 -0600 Subject: [PATCH 05/19] fix mypy issues --- src/schematic/datastream/datastream_client.py | 14 +++++++------- src/schematic/datastream/websocket_client.py | 2 +- tests/datastream/test_merge.py | 7 ++++++- tests/datastream/test_websocket_client.py | 6 +++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index b4307aa..fcae9cb 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -53,7 +53,7 @@ def _coerce_nulls(data: dict, model_cls: type) -> dict: def _validate(model_cls: type, raw: Any) -> Any: """Validate raw data into a Pydantic model, coercing Go-style nulls first.""" if isinstance(raw, dict): - return model_cls.model_validate(_coerce_nulls(raw, model_cls)) + return model_cls.model_validate(_coerce_nulls(raw, model_cls)) # type: ignore[attr-defined] return raw @@ -396,8 +396,8 @@ async def check_flag( else: tasks.append(_resolved(cached_user)) - company, user = await asyncio.gather(*tasks) - return self._evaluate_flag(flag, company, user) + results: list = await asyncio.gather(*tasks) + return self._evaluate_flag(flag, results[0], results[1]) async def update_company_metrics(self, keys: Dict[str, str], event: str, quantity: int) -> None: """Update company metrics locally in cache (for track events).""" @@ -893,10 +893,10 @@ def _clear_pending_requests(self) -> None: fut.set_exception(RuntimeError("DataStream client disconnected")) self._pending_company.clear() - for futures in self._pending_user.values(): - for fut in futures: - if not fut.done(): - fut.set_exception(RuntimeError("DataStream client disconnected")) + for user_futures in self._pending_user.values(): + for user_fut in user_futures: + if not user_fut.done(): + user_fut.set_exception(RuntimeError("DataStream client disconnected")) self._pending_user.clear() if self._pending_flags is not None and not self._pending_flags.done(): diff --git a/src/schematic/datastream/websocket_client.py b/src/schematic/datastream/websocket_client.py index 29d4797..d15ec05 100644 --- a/src/schematic/datastream/websocket_client.py +++ b/src/schematic/datastream/websocket_client.py @@ -112,7 +112,7 @@ def __init__(self, options: ClientOptions) -> None: raise ValueError("url is required") if not options.api_key: raise ValueError("api_key is required") - if not options.message_handler: + if options.message_handler is None: # type: ignore[operator] raise ValueError("message_handler is required") # Auto-convert HTTP(S) URLs to WebSocket URLs diff --git a/tests/datastream/test_merge.py b/tests/datastream/test_merge.py index a456336..6f263a8 100644 --- a/tests/datastream/test_merge.py +++ b/tests/datastream/test_merge.py @@ -221,7 +221,7 @@ def test_sets_base_plan_to_none(self) -> None: class TestPartialCompanyMissingID: def test_raises_value_error(self) -> None: existing = base_company() - partial = {"traits": []} + partial: dict[str, list[str]] = {"traits": []} with pytest.raises(ValueError, match="missing required field: id"): partial_company(existing, partial) @@ -314,6 +314,7 @@ def test_full_entity_partial_message(self) -> None: # Credit balances merge: existing credit-1 overwritten, credit-new added assert merged.credit_balances == {"credit-1": 999.0, "credit-new": 50.0} + assert merged.entitlements is not None assert len(merged.entitlements) == 2 assert merged.entitlements[0].feature_id == "feat-new" assert merged.entitlements[1].feature_id == "feat-2" @@ -493,6 +494,7 @@ def test_full_copy_is_independent(self) -> None: ) cp = deep_copy_company(orig) + assert cp is not None assert cp.id == orig.id assert cp.account_id == orig.account_id @@ -500,6 +502,7 @@ def test_full_copy_is_independent(self) -> None: assert cp.base_plan_id == orig.base_plan_id assert cp.keys == orig.keys assert cp.credit_balances == orig.credit_balances + assert cp.subscription is not None assert cp.subscription.id == "sub-1" assert cp.metrics[0].value == 42 @@ -518,6 +521,7 @@ def test_empty_fields(self) -> None: rules=[], ) cp = deep_copy_user(orig) + assert cp is not None assert cp.id == "u1" assert cp.keys == {} @@ -528,6 +532,7 @@ def test_full_copy_is_independent(self) -> None: orig = base_user().model_copy(update={"rules": [_make_rule("r1")]}) cp = deep_copy_user(orig) + assert cp is not None assert cp.id == orig.id assert cp.account_id == orig.account_id diff --git a/tests/datastream/test_websocket_client.py b/tests/datastream/test_websocket_client.py index d7ff10a..1426c6b 100644 --- a/tests/datastream/test_websocket_client.py +++ b/tests/datastream/test_websocket_client.py @@ -171,7 +171,7 @@ async def handler(msg): pass def test_init_missing_message_handler() -> None: with pytest.raises(ValueError, match="message_handler is required"): DatastreamWSClient( - ClientOptions(url="wss://example.com", api_key="key", message_handler=None, logger=logger) + ClientOptions(url="wss://example.com", api_key="key", message_handler=None, logger=logger) # type: ignore[arg-type] ) @@ -236,7 +236,7 @@ async def test_string_message_delivered_to_handler() -> None: async def test_bytes_message_delivered_to_handler() -> None: payload = json.dumps({"entity_type": "rulesengine.Flag", "message_type": "full", "data": None}) - ws = MockWebSocket(messages=[payload.encode()]) + ws = MockWebSocket(messages=[payload.encode()]) # type: ignore[list-item] client, ws, received = make_client(ws=ws) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): @@ -431,7 +431,7 @@ async def test_stops_at_max_reconnect_attempts() -> None: ClientOptions( url="wss://test.example.com/datastream", api_key="key", - message_handler=lambda _: None, + message_handler=lambda _: None, # type: ignore[arg-type,return-value] logger=logger, min_reconnect_delay=0.0, max_reconnect_delay=0.0, From dec5d76d49b2a0e0bac18b6e9b46093d5b2c1504 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 13:15:25 -0600 Subject: [PATCH 06/19] add wasmtime in ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4588ce..80b9954 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Install dependencies - run: poetry install + run: poetry install --extras rulesengine - name: Compile run: poetry run mypy . test: @@ -30,7 +30,7 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Install dependencies - run: poetry install + run: poetry install --extras rulesengine - name: Test run: poetry run pytest -rP -n auto . From 51bbd3055a7c0681f8cde02018860daf0d60a930 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 14:02:16 -0600 Subject: [PATCH 07/19] fix issues with websocket connections not reconnecting and closing properly --- src/schematic/datastream/websocket_client.py | 16 ++++ tests/datastream/test_websocket_client.py | 83 ++++++++++---------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/schematic/datastream/websocket_client.py b/src/schematic/datastream/websocket_client.py index d15ec05..a817de0 100644 --- a/src/schematic/datastream/websocket_client.py +++ b/src/schematic/datastream/websocket_client.py @@ -191,6 +191,16 @@ async def close(self) -> None: pass self._ws = None + # Cancel and await the ping task + if self._ping_task is not None: + self._ping_task.cancel() + try: + await self._ping_task + except (asyncio.CancelledError, Exception): + pass + self._ping_task = None + + # Cancel and await the main connection task if self._task is not None: self._task.cancel() try: @@ -226,7 +236,13 @@ async def _connect_and_read(self) -> None: await self._connection_ready_handler() self._logger.debug("Connection ready handler completed successfully") except Exception as err: + self._reconnect_attempts += 1 self._logger.error(f"Connection ready handler failed: {err}") + if self._reconnect_attempts >= self._max_reconnect_attempts: + self._logger.error("Max reconnection attempts reached") + if self._on_error is not None: + self._on_error(Exception("Max reconnection attempts reached")) + break continue self._set_ready(True) diff --git a/tests/datastream/test_websocket_client.py b/tests/datastream/test_websocket_client.py index 1426c6b..18be616 100644 --- a/tests/datastream/test_websocket_client.py +++ b/tests/datastream/test_websocket_client.py @@ -125,6 +125,16 @@ async def _poll(): await asyncio.wait_for(_poll(), timeout=timeout) +@asynccontextmanager +async def run_client(client: DatastreamWSClient): + """Context manager that ensures client.close() is always called.""" + client.start() + try: + yield client + finally: + await client.close() + + # --------------------------------------------------------------------------- # convert_api_url_to_websocket_url # --------------------------------------------------------------------------- @@ -203,16 +213,14 @@ async def test_send_message_sends_json_when_connected() -> None: client, ws, _ = make_client(ws=ws, on_connected=lambda: connected.set()) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await asyncio.wait_for(connected.wait(), timeout=2.0) - - req = DataStreamBaseReq(data=DataStreamReq(entity_type=EntityType.COMPANY)) - await client.send_message(req) + async with run_client(client): + await asyncio.wait_for(connected.wait(), timeout=2.0) - assert len(ws.sent) == 1 - assert json.loads(ws.sent[0]) == {"data": {"entity_type": "rulesengine.Company"}} + req = DataStreamBaseReq(data=DataStreamReq(entity_type=EntityType.COMPANY)) + await client.send_message(req) - await client.close() + assert len(ws.sent) == 1 + assert json.loads(ws.sent[0]) == {"data": {"action": "start", "entity_type": "company"}} # --------------------------------------------------------------------------- @@ -225,9 +233,8 @@ async def test_string_message_delivered_to_handler() -> None: client, ws, received = make_client(messages=[msg]) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(lambda: len(received) == 1) - await client.close() + async with run_client(client): + await wait_until(lambda: len(received) == 1) assert received[0].entity_type == "rulesengine.Company" assert received[0].message_type == "full" @@ -240,9 +247,8 @@ async def test_bytes_message_delivered_to_handler() -> None: client, ws, received = make_client(ws=ws) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(lambda: len(received) == 1) - await client.close() + async with run_client(client): + await wait_until(lambda: len(received) == 1) assert received[0].entity_type == "rulesengine.Flag" @@ -252,9 +258,8 @@ async def test_invalid_json_calls_on_error() -> None: client, ws, _ = make_client(messages=["not-valid-json"], on_error=errors.append) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(lambda: len(errors) > 0) - await client.close() + async with run_client(client): + await wait_until(lambda: len(errors) > 0) assert "Failed to parse" in str(errors[0]) @@ -280,9 +285,8 @@ async def bad_handler(msg: DataStreamResp) -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(lambda: len(errors) > 0) - await client.close() + async with run_client(client): + await wait_until(lambda: len(errors) > 0) assert "Message handler error" in str(errors[0]) @@ -304,15 +308,13 @@ async def test_on_connected_and_on_ready_fired() -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(client.is_ready) + async with run_client(client): + await wait_until(client.is_ready) - assert connected_calls == [True] - assert ready_calls == [True] - assert client.is_connected() - assert client.is_ready() - - await client.close() + assert connected_calls == [True] + assert ready_calls == [True] + assert client.is_connected() + assert client.is_ready() async def test_on_disconnected_and_on_not_ready_fired_on_close() -> None: @@ -327,9 +329,8 @@ async def test_on_disconnected_and_on_not_ready_fired_on_close() -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(client.is_connected) - await client.close() + async with run_client(client): + await wait_until(client.is_connected) assert True in disconnected_calls assert True in not_ready_calls @@ -356,11 +357,10 @@ async def ready_handler() -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await wait_until(client.is_ready) + async with run_client(client): + await wait_until(client.is_ready) - assert order == ["ready_handler", "on_ready"] - await client.close() + assert order == ["ready_handler", "on_ready"] async def test_connection_ready_handler_failure_prevents_ready() -> None: @@ -375,8 +375,8 @@ async def failing_handler() -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", make_connect(ws)): - client.start() - await asyncio.sleep(0.1) + async with run_client(client): + await asyncio.sleep(0.1) assert not client.is_ready() @@ -416,9 +416,8 @@ async def handler(m: DataStreamResp) -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", mock_connect): - client.start() - await wait_until(lambda: len(received) == 1) - await client.close() + async with run_client(client): + await wait_until(lambda: len(received) == 1) assert len(connect_calls) >= 2 assert len(received) == 1 @@ -441,8 +440,8 @@ async def test_stops_at_max_reconnect_attempts() -> None: ) with patch("schematic.datastream.websocket_client.websockets.connect", _AlwaysFailConnect()): - client.start() - await wait_until(lambda: len(errors) > 0) + async with run_client(client): + await wait_until(lambda: len(errors) > 0) assert "Max reconnection" in str(errors[0]) From 63f1e1e833c48b2c81250aa5a15ff1090c258c4d Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 14:23:31 -0600 Subject: [PATCH 08/19] remove unused function --- src/schematic/client.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/schematic/client.py b/src/schematic/client.py index 44c45e3..c46287a 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -144,12 +144,10 @@ def _check_flag_via_api( value=default_value, ) - result = _api_response_to_result(resp.data) - for provider in self.flag_check_cache_providers: - provider.set(cache_key, result) + provider.set(cache_key, resp.data) - return result + return resp.data except Exception as e: self.logger.error(e) return CheckFlagResponseData( @@ -429,12 +427,10 @@ async def _check_flag_via_api( value=default_value, ) - result = _api_response_to_result(resp.data) - for provider in self.flag_check_cache_providers: - provider.set(cache_key, result) + provider.set(cache_key, resp.data) - return result + return resp.data except Exception as e: self.logger.error(e) return CheckFlagResponseData( @@ -558,7 +554,3 @@ def _build_cache_key( if company or user: return flag_key + ":" + str(company) + ":" + str(user) return flag_key - - -def _api_response_to_result(data: CheckFlagResponseData) -> CheckFlagResponseData: - return data From 98b62d7cc3187dc2fd35820d6120d014cb769e55 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 14:27:15 -0600 Subject: [PATCH 09/19] Remove fire-and-forget sync close() in favor of single async close() method --- src/schematic/client.py | 2 +- src/schematic/datastream/datastream_client.py | 21 ++----------------- tests/datastream/test_datastream_client.py | 2 +- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/schematic/client.py b/src/schematic/client.py index c46287a..5e3623f 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -533,7 +533,7 @@ async def shutdown(self) -> None: try: if self._datastream_client is not None: try: - await self._datastream_client.close_async() + await self._datastream_client.close() except Exception as e: self.logger.error(f"Error closing DataStream client: {e}") diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index fcae9cb..e032601 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -120,7 +120,7 @@ class DataStreamClient: )) await client.start() result = await client.check_flag(CheckFlagRequestBody(company={"id": "co_123"}), "premium-feature") - client.close() + await client.close() """ def __init__(self, options: DataStreamClientOptions) -> None: @@ -416,7 +416,7 @@ async def update_company_metrics(self, keys: Dict[str, str], event: str, quantit await self._cache_company(updated) - def close(self) -> None: + async def close(self) -> None: """Gracefully close the datastream client.""" self._logger.info("Closing DataStream client") @@ -426,23 +426,6 @@ def close(self) -> None: self._clear_pending_requests() - if self._ws_client is not None: - # Schedule the async close — caller should await if needed - asyncio.ensure_future(self._ws_client.close()) - self._ws_client = None - - self._logger.info("DataStream client closed") - - async def close_async(self) -> None: - """Async version of close that awaits the websocket shutdown.""" - self._logger.info("Closing DataStream client") - - if self._replicator_health_task is not None: - self._replicator_health_task.cancel() - self._replicator_health_task = None - - self._clear_pending_requests() - if self._ws_client is not None: await self._ws_client.close() self._ws_client = None diff --git a/tests/datastream/test_datastream_client.py b/tests/datastream/test_datastream_client.py index c7462cb..dfefbb2 100644 --- a/tests/datastream/test_datastream_client.py +++ b/tests/datastream/test_datastream_client.py @@ -291,7 +291,7 @@ async def test_close_cleans_up(self, logger: logging.Logger) -> None: user_lookup_cache=cache, flag_cache=cache, )) - client.close() # Should not raise + await client.close() # Should not raise class TestDataStreamClientCacheKeys: From 567d14620fb2fd5f8368bc5d947d1ec47e531082 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 14:29:34 -0600 Subject: [PATCH 10/19] remove per-call import of typing library --- src/schematic/datastream/datastream_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index e032601..5124235 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -3,6 +3,7 @@ import asyncio import json import logging +import typing from dataclasses import dataclass, field from typing import Any, Callable, Dict, List, Optional, Set, Union @@ -24,7 +25,6 @@ def _coerce_nulls(data: dict, model_cls: type) -> dict: Go serializes nil slices as JSON null, but our Pydantic models require lists. This recursively fixes nulls before model_validate. """ - import typing if not hasattr(model_cls, "__annotations__"): return data From 69d2a7595f5f04a9ef8eb4bb8b38450a10af97ab Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 25 Mar 2026 14:45:03 -0600 Subject: [PATCH 11/19] miscellaneous fixes --- src/schematic/cache/local.py | 29 +- src/schematic/client.py | 29 +- src/schematic/datastream/datastream_client.py | 8 +- src/schematic/datastream/rules_engine.py | 22 +- tests/datastream/test_datastream_client.py | 302 ++++++++++++++++++ 5 files changed, 343 insertions(+), 47 deletions(-) diff --git a/src/schematic/cache/local.py b/src/schematic/cache/local.py index f14f8b8..abc6717 100644 --- a/src/schematic/cache/local.py +++ b/src/schematic/cache/local.py @@ -10,8 +10,10 @@ DEFAULT_CACHE_SIZE = 1000 DEFAULT_CACHE_TTL = 5000 # 5 seconds -DEFAULT_MAX_ITEMS = 1000 -DEFAULT_TTL_MS = 5000 + +# Aliases for backwards compatibility +DEFAULT_MAX_ITEMS = DEFAULT_CACHE_SIZE +DEFAULT_TTL_MS = DEFAULT_CACHE_TTL class CachedItem(Generic[T]): @@ -67,11 +69,10 @@ def clean_expired(self) -> None: class _AsyncCacheItem(Generic[T]): - __slots__ = ("value", "access_counter", "expiration") + __slots__ = ("value", "expiration") - def __init__(self, value: T, access_counter: int, expiration: float) -> None: + def __init__(self, value: T, expiration: float) -> None: self.value = value - self.access_counter = access_counter self.expiration = expiration @@ -82,7 +83,6 @@ def __init__(self, *, max_items: int = DEFAULT_MAX_ITEMS, ttl: int = DEFAULT_TTL self._cache: OrderedDict[str, _AsyncCacheItem[Any]] = OrderedDict() self._max_items = max_items self._default_ttl = ttl - self._access_counter = 0 async def get(self, key: str) -> Optional[T]: item = self._cache.get(key) @@ -94,8 +94,6 @@ async def get(self, key: str) -> Optional[T]: del self._cache[key] return None - self._access_counter += 1 - item.access_counter = self._access_counter self._cache.move_to_end(key) return item.value @@ -111,22 +109,11 @@ async def set(self, key: str, value: T, ttl: Optional[int] = None) -> None: self._evict_expired() while len(self._cache) >= self._max_items: - oldest_key: Optional[str] = None - oldest_counter = float("inf") - for k, item in self._cache.items(): - if item.access_counter < oldest_counter: - oldest_key = k - oldest_counter = item.access_counter - if oldest_key is not None: - del self._cache[oldest_key] - else: - break - - self._access_counter += 1 + self._cache.popitem(last=False) + now_ms = time.time() * 1000 self._cache[key] = _AsyncCacheItem( value=value, - access_counter=self._access_counter, expiration=now_ms + effective_ttl, ) diff --git a/src/schematic/client.py b/src/schematic/client.py index 5e3623f..1ba9170 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -20,6 +20,7 @@ EventBodyIdentify, EventBodyIdentifyCompany, EventBodyTrack, + FeatureEntitlement, ) @@ -378,25 +379,29 @@ async def check_flag_with_entitlement( flag_key=flag_key, value=resp.value if resp.value is not None else False, reason=resp.reason if resp.reason else "unknown", - rule_id=getattr(resp, "rule_id", None), - company_id=getattr(resp, "company_id", None), - user_id=getattr(resp, "user_id", None), - flag_id=getattr(resp, "flag_id", None), + rule_id=resp.rule_id, + company_id=resp.company_id, + user_id=resp.user_id, + flag_id=resp.flag_id, req_company=company, req_user=user, ), ) + entitlement = ( + FeatureEntitlement.model_validate(resp.entitlement.model_dump(mode="json")) + if resp.entitlement is not None else None + ) return CheckFlagResponseData( - company_id=getattr(resp, "company_id", None), - entitlement=getattr(resp, "entitlement", None), - error=getattr(resp, "err", None), - flag=getattr(resp, "flag", flag_key), - flag_id=getattr(resp, "flag_id", None), + company_id=resp.company_id, + entitlement=entitlement, + error=resp.err, + flag=resp.flag_key, + flag_id=resp.flag_id, reason=resp.reason, - rule_id=getattr(resp, "rule_id", None), - rule_type=getattr(resp, "rule_type", None), - user_id=getattr(resp, "user_id", None), + rule_id=resp.rule_id, + rule_type=resp.rule_type, + user_id=resp.user_id, value=resp.value if resp.value is not None else self._get_flag_default(flag_key), ) except Exception as e: diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index 5124235..251794b 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -89,7 +89,7 @@ class DataStreamClientOptions: # Replicator mode replicator_mode: bool = False - replicator_health_url: Optional[str] = None + replicator_health_url: Optional[str] = "http://localhost:8090/ready" replicator_health_check: int = DEFAULT_REPLICATOR_HEALTH_CHECK_MS # Event callbacks @@ -658,7 +658,8 @@ async def _get_company_from_cache(self, keys: Dict[str, str]) -> Optional[Rulese raw = await self._company_cache.get(rk) self._logger.debug("Company ID key %s -> %s", rk, "hit" if raw is not None else "miss") if raw is not None: - return _validate(RulesengineCompany, raw) + company = _validate(RulesengineCompany, raw) + return company.model_copy(deep=True) except Exception as exc: self._logger.warning("Failed to retrieve company from cache: %s", exc) return None @@ -672,7 +673,8 @@ async def _get_user_from_cache(self, keys: Dict[str, str]) -> Optional[Rulesengi rk = self._resource_id_cache_key(_PREFIX_USER, user_id) raw = await self._user_cache.get(rk) if raw is not None: - return _validate(RulesengineUser, raw) + user = _validate(RulesengineUser, raw) + return user.model_copy(deep=True) except Exception as exc: self._logger.warning("Failed to retrieve user from cache: %s", exc) return None diff --git a/src/schematic/datastream/rules_engine.py b/src/schematic/datastream/rules_engine.py index 7f3dc1b..9bb14fe 100644 --- a/src/schematic/datastream/rules_engine.py +++ b/src/schematic/datastream/rules_engine.py @@ -1,6 +1,5 @@ from __future__ import annotations -import ctypes import json import logging from pathlib import Path @@ -134,7 +133,7 @@ def get_version_key(self) -> str: return "1" ptr = self._get_version_key_fn(self._store) - return self._read_memory(ptr, 8).decode("utf-8") + return self._read_null_terminated_string(ptr) # ------------------------------------------------------------------ # Internal helpers @@ -155,8 +154,7 @@ def _call_wasm(self, input_json: str) -> str: # Allocate a buffer inside WASM memory and copy our JSON into it ptr = self._alloc_fn(self._store, length) try: - base = ctypes.addressof(self._memory.data_ptr(self._store).contents) - ctypes.memmove(base + ptr, data, length) + self._memory.write(self._store, data, ptr) result_len = self._check_flag_fn(self._store, ptr, length) if result_len < 0: @@ -167,10 +165,12 @@ def _call_wasm(self, input_json: str) -> str: # Read the result (owned by WASM thread-local, no need to free) result_ptr = self._get_result_json_fn(self._store) actual_len = self._get_result_json_length_fn(self._store) - return self._read_memory(result_ptr, actual_len).decode("utf-8") - - def _read_memory(self, ptr: int, length: int) -> bytes: - """Read *length* bytes from WASM linear memory at *ptr*.""" - base = ctypes.addressof(self._memory.data_ptr(self._store).contents) - src = (ctypes.c_ubyte * length).from_address(base + ptr) - return bytes(src) + return bytes(self._memory.read(self._store, result_ptr, result_ptr + actual_len)).decode("utf-8") + + def _read_null_terminated_string(self, ptr: int, max_length: int = 256) -> str: + """Read a null-terminated UTF-8 string from WASM linear memory.""" + raw = self._memory.read(self._store, ptr, ptr + max_length) + null_idx = raw.find(0) + if null_idx >= 0: + raw = raw[:null_idx] + return raw.decode("utf-8") diff --git a/tests/datastream/test_datastream_client.py b/tests/datastream/test_datastream_client.py index dfefbb2..9f96c8a 100644 --- a/tests/datastream/test_datastream_client.py +++ b/tests/datastream/test_datastream_client.py @@ -356,3 +356,305 @@ async def test_check_flag_raises_when_flag_not_found(self, logger: logging.Logge )) with pytest.raises(RuntimeError, match="Flag not found"): await client.check_flag(CheckFlagRequestBody(), "nonexistent-flag") + + async def test_flag_evaluation_with_cached_company(self, logger: logging.Logger) -> None: + """Spec test #6: Flag evaluation with cached company.""" + from schematic.types import RulesengineFlag + + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + + # Cache a company via full message + await client._handle_message(DataStreamResp( + data={ + "id": "co_eval", + "keys": {"slug": "eval-co"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": [], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.FULL.value, + )) + + # Cache a flag + await client._handle_message(DataStreamResp( + data={"key": "co-flag", "id": "f1", "default_value": True, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + entity_type=EntityType.FLAG.value, + message_type=MessageType.FULL.value, + )) + + result = await client.check_flag( + CheckFlagRequestBody(company={"slug": "eval-co"}), + "co-flag", + ) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.company_id == "co_eval" + assert result.flag_key == "co-flag" + + async def test_flag_evaluation_with_cached_user(self, logger: logging.Logger) -> None: + """Spec test #7: Flag evaluation with cached user.""" + from schematic.types import RulesengineFlag + + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + + # Cache a user + await client._handle_message(DataStreamResp( + data={ + "id": "usr_eval", + "keys": {"email": "eval@test.com"}, + "account_id": "acc_1", + "environment_id": "env_1", + "rules": [], + "traits": [], + }, + entity_type=EntityType.USER.value, + message_type=MessageType.FULL.value, + )) + + # Cache a flag + await client._handle_message(DataStreamResp( + data={"key": "usr-flag", "id": "f2", "default_value": False, "rules": [], "account_id": "acc_1", "environment_id": "env_1"}, + entity_type=EntityType.FLAG.value, + message_type=MessageType.FULL.value, + )) + + result = await client.check_flag( + CheckFlagRequestBody(user={"email": "eval@test.com"}), + "usr-flag", + ) + assert isinstance(result, RulesengineCheckFlagResult) + assert result.user_id == "usr_eval" + assert result.flag_key == "usr-flag" + + +class TestDataStreamClientPartialMerge: + """Spec test #4: Partial entity message merges into cache.""" + + @pytest.fixture + def client_with_cache(self, logger: logging.Logger) -> tuple[DataStreamClient, MockCacheProvider]: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + return client, cache + + async def test_partial_company_merges_keys( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider], + ) -> None: + client, _ = client_with_cache + + # Add full company + await client._handle_message(DataStreamResp( + data={ + "id": "co_partial", + "keys": {"slug": "original"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": [], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.FULL.value, + )) + + # Partial update adds a new key + await client._handle_message(DataStreamResp( + data={"id": "co_partial", "keys": {"domain": "example.com"}}, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.PARTIAL.value, + )) + + company = await client._get_company_from_cache({"slug": "original"}) + assert company is not None + assert company.keys == {"slug": "original", "domain": "example.com"} + + async def test_partial_user_merges_keys( + self, + client_with_cache: tuple[DataStreamClient, MockCacheProvider], + ) -> None: + client, _ = client_with_cache + + # Add full user + await client._handle_message(DataStreamResp( + data={ + "id": "usr_partial", + "keys": {"email": "orig@test.com"}, + "account_id": "acc_1", + "environment_id": "env_1", + "rules": [], + "traits": [], + }, + entity_type=EntityType.USER.value, + message_type=MessageType.FULL.value, + )) + + # Partial update adds a new key + await client._handle_message(DataStreamResp( + data={"id": "usr_partial", "keys": {"slack_id": "U123"}}, + entity_type=EntityType.USER.value, + message_type=MessageType.PARTIAL.value, + )) + + user = await client._get_user_from_cache({"email": "orig@test.com"}) + assert user is not None + assert user.keys == {"email": "orig@test.com", "slack_id": "U123"} + + +class TestDataStreamClientDeepCopy: + """Spec test #12: Deep copy prevents mutation of cached entities.""" + + async def test_cached_company_mutation_does_not_affect_cache(self, logger: logging.Logger) -> None: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + + await client._handle_message(DataStreamResp( + data={ + "id": "co_mut", + "keys": {"slug": "mutable"}, + "account_id": "acc_1", + "environment_id": "env_1", + "billing_product_ids": ["bp-1"], + "credit_balances": {}, + "metrics": [], + "plan_ids": [], + "plan_version_ids": [], + "rules": [], + "traits": [], + }, + entity_type=EntityType.COMPANY.value, + message_type=MessageType.FULL.value, + )) + + # Retrieve and mutate + company = await client._get_company_from_cache({"slug": "mutable"}) + assert company is not None + original_ids = list(company.billing_product_ids) + company.billing_product_ids.append("bp-INJECTED") + + # Re-retrieve — cache should be unaffected + fresh = await client._get_company_from_cache({"slug": "mutable"}) + assert fresh is not None + assert fresh.billing_product_ids == original_ids + + async def test_cached_user_mutation_does_not_affect_cache(self, logger: logging.Logger) -> None: + cache = MockCacheProvider() + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_mode=True, + company_cache=cache, + company_lookup_cache=cache, + user_cache=cache, + user_lookup_cache=cache, + flag_cache=cache, + )) + + await client._handle_message(DataStreamResp( + data={ + "id": "usr_mut", + "keys": {"email": "mut@test.com"}, + "account_id": "acc_1", + "environment_id": "env_1", + "rules": [], + "traits": [], + }, + entity_type=EntityType.USER.value, + message_type=MessageType.FULL.value, + )) + + user = await client._get_user_from_cache({"email": "mut@test.com"}) + assert user is not None + user.keys["injected"] = "bad" + + fresh = await client._get_user_from_cache({"email": "mut@test.com"}) + assert fresh is not None + assert "injected" not in fresh.keys + + +class TestDataStreamClientMissingEntityTimeout: + """Spec test #8: Missing company triggers fetch/wait (times out without WS).""" + + async def test_get_company_times_out_without_connection(self, logger: logging.Logger) -> None: + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + base_url="https://api.schematichq.com", + logger=logger, + )) + with pytest.raises(RuntimeError, match="not connected"): + await client.get_company({"slug": "missing"}) + + async def test_get_user_times_out_without_connection(self, logger: logging.Logger) -> None: + client = DataStreamClient(DataStreamClientOptions( + api_key="test-key", + base_url="https://api.schematichq.com", + logger=logger, + )) + with pytest.raises(RuntimeError, match="not connected"): + await client.get_user({"email": "missing@test.com"}) + + +class TestDataStreamClientDefaultReplicatorHealthUrl: + """Verify replicator_health_url defaults to spec canonical value.""" + + def test_default_health_url(self, logger: logging.Logger) -> None: + opts = DataStreamClientOptions( + api_key="test-key", + logger=logger, + ) + assert opts.replicator_health_url == "http://localhost:8090/ready" + + def test_custom_health_url_overrides_default(self, logger: logging.Logger) -> None: + opts = DataStreamClientOptions( + api_key="test-key", + logger=logger, + replicator_health_url="http://custom:9090/health", + ) + assert opts.replicator_health_url == "http://custom:9090/health" From db842e3ce79777778bb9d4e78158ce84b295b4a5 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 26 Mar 2026 08:23:53 -0600 Subject: [PATCH 12/19] add readme --- README.md | 123 ++++++++++++++++++ src/schematic/cache/provider.py | 4 +- src/schematic/datastream/datastream_client.py | 12 +- 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bba4b80..787db32 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,129 @@ client.check_flag( ) ``` +## DataStream + +The DataStream functionality provides real-time updates for flags, companies, and users. It uses WebSocket connections to receive updates from the Schematic backend and evaluates feature flags locally using a WASM rules engine, reducing the number of network calls. + +### Requirements + +DataStream requires the `rulesengine` extra for local flag evaluation: + +```bash +pip install schematichq[rulesengine] +# or +poetry add schematichq -E rulesengine +``` + +### Key Features + +- **Real-Time Updates**: Automatically updates cached data when changes occur on the backend. +- **Local Flag Evaluation**: Flag checks are evaluated locally via WASM, eliminating per-check network requests. +- **Configurable Caching**: Supports both in-memory caching and custom cache providers (e.g. Redis). + +### How to Enable DataStream + +To enable DataStream, set `use_datastream=True` in your `AsyncSchematicConfig`: + +```python +import asyncio +from schematic.client import AsyncSchematic, AsyncSchematicConfig, DataStreamConfig + +async def main(): + config = AsyncSchematicConfig( + use_datastream=True, + ) + + async with AsyncSchematic("YOUR_API_KEY", config) as client: + is_enabled = await client.check_flag( + "some-flag-key", + company={"id": "your-company-id"}, + user={"id": "your-user-id"}, + ) + +asyncio.run(main()) +``` + +### Configuring Cache TTL + +You can customize the cache TTL (in milliseconds) via the `DataStreamConfig`: + +```python +config = AsyncSchematicConfig( + use_datastream=True, + datastream=DataStreamConfig( + cache_ttl=300_000, # 5 minutes + ), +) +``` + +### Replicator Mode + +When running the `schematic-datastream-replicator` service, configure the client to operate in Replicator Mode. In this mode, the client skips establishing its own WebSocket connection and instead relies on a shared cache populated by the external replicator service. + +```python +import asyncio +from schematic.client import AsyncSchematic, AsyncSchematicConfig, DataStreamConfig + +async def main(): + config = AsyncSchematicConfig( + use_datastream=True, + datastream=DataStreamConfig( + replicator_mode=True, + ), + ) + + async with AsyncSchematic("YOUR_API_KEY", config) as client: + is_enabled = await client.check_flag( + "some-flag-key", + company={"id": "your-company-id"}, + ) + +asyncio.run(main()) +``` + +#### Cache TTL Configuration + +When using Replicator Mode, you should set the SDK's cache TTL to match the replicator's cache TTL. The replicator defaults to an unlimited cache TTL (`0`). If the SDK uses a shorter TTL (the default is 24 hours), locally updated cache entries will be written back with the shorter TTL and eventually evicted from the shared cache. + +To match the replicator's default unlimited TTL: + +```python +config = AsyncSchematicConfig( + use_datastream=True, + datastream=DataStreamConfig( + replicator_mode=True, + cache_ttl=0, # Unlimited, matching the replicator default + ), +) +``` + +#### Advanced Configuration + +```python +config = AsyncSchematicConfig( + use_datastream=True, + datastream=DataStreamConfig( + replicator_mode=True, + cache_ttl=0, + replicator_health_url="http://my-replicator:8090/ready", + replicator_health_check=60_000, # 60 seconds, in milliseconds + ), +) +``` + +#### Default Configuration + +- **Replicator Health URL**: `http://localhost:8090/ready` +- **Health Check Interval**: 30 seconds +- **Cache TTL**: 24 hours (SDK default; should be set to match the replicator's TTL, which defaults to unlimited) + +When running in Replicator Mode, the client will: +- Skip establishing WebSocket connections +- Periodically check if the replicator service is ready +- Use cached data populated by the external replicator service +- Fall back to direct API calls if the replicator is not available + ## Webhook Verification Schematic can send webhooks to notify your application of events. To ensure the security of these webhooks, Schematic signs each request using HMAC-SHA256. The Python SDK provides utility functions to verify these signatures. diff --git a/src/schematic/cache/provider.py b/src/schematic/cache/provider.py index 1757e93..d61f138 100644 --- a/src/schematic/cache/provider.py +++ b/src/schematic/cache/provider.py @@ -9,10 +9,10 @@ class CacheProvider(Generic[T]): """Synchronous cache provider interface.""" def get(self, key: str) -> Optional[T]: - pass + raise NotImplementedError def set(self, key: str, val: T, ttl_override: Optional[int] = None) -> None: - pass + raise NotImplementedError class AsyncCacheProvider(Generic[T]): diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index 251794b..abcac0e 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -19,6 +19,16 @@ from .websocket_client import ClientOptions as WSClientOptions, DatastreamWSClient +_hints_cache: Dict[type, Dict[str, Any]] = {} + + +def _get_type_hints(model_cls: type) -> Dict[str, Any]: + """Cached wrapper around typing.get_type_hints to avoid repeated introspection.""" + if model_cls not in _hints_cache: + _hints_cache[model_cls] = typing.get_type_hints(model_cls) + return _hints_cache[model_cls] + + def _coerce_nulls(data: dict, model_cls: type) -> dict: """Convert null values to empty lists for required list fields. @@ -28,7 +38,7 @@ def _coerce_nulls(data: dict, model_cls: type) -> dict: if not hasattr(model_cls, "__annotations__"): return data - hints = typing.get_type_hints(model_cls) + hints = _get_type_hints(model_cls) result = dict(data) for field_name, field_type in hints.items(): if field_name not in result: From 1664c04cc3adda09feadf99acd8ca4c9d642aaaf Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 26 Mar 2026 09:09:05 -0600 Subject: [PATCH 13/19] add casing assertions --- src/schematic/datastream/rules_engine.py | 19 +++++++++++++++++- .../datastream/wasm/rulesengine.wasm | Bin 615067 -> 577191 bytes tests/datastream/test_rules_engine.py | 7 +++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/schematic/datastream/rules_engine.py b/src/schematic/datastream/rules_engine.py index 9bb14fe..a4fde5b 100644 --- a/src/schematic/datastream/rules_engine.py +++ b/src/schematic/datastream/rules_engine.py @@ -2,6 +2,7 @@ import json import logging +import re from pathlib import Path from typing import Any, Optional @@ -12,6 +13,22 @@ logger = logging.getLogger(__name__) +_CAMEL_RE = re.compile(r"([A-Z])") + + +def _camel_to_snake(name: str) -> str: + """Convert a camelCase string to snake_case.""" + return _CAMEL_RE.sub(r"_\1", name).lower().lstrip("_") + + +def _deep_camel_to_snake(obj: Any) -> Any: + """Recursively convert all dict keys from camelCase to snake_case.""" + if isinstance(obj, dict): + return {_camel_to_snake(k): _deep_camel_to_snake(v) for k, v in obj.items()} + if isinstance(obj, list): + return [_deep_camel_to_snake(item) for item in obj] + return obj + # Path to the WASM binary shipped alongside this module _WASM_PATH = Path(__file__).parent / "wasm" / "rulesengine.wasm" @@ -119,7 +136,7 @@ def check_flag( } result_json = self._call_wasm(json.dumps(envelope)) - result_data = json.loads(result_json) + result_data = _deep_camel_to_snake(json.loads(result_json)) return RulesengineCheckFlagResult(**result_data) def get_version_key(self) -> str: diff --git a/src/schematic/datastream/wasm/rulesengine.wasm b/src/schematic/datastream/wasm/rulesengine.wasm index 7a64e670fd77a4b2752f2cfed3f85f407242ea2a..a5c7a5a5ca1920972b161cf7f303a48bfbfad3fa 100755 GIT binary patch delta 127229 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 @;5@m5QALISIftCL4q4@2lsy+^Q35V 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 None: from schematic.types import RulesengineCompany @@ -99,6 +101,9 @@ async def test_evaluates_flag_with_company_context(self, engine: RulesEngineClie result = engine.check_flag(flag, company) assert isinstance(result, RulesengineCheckFlagResult) assert result.value is True + assert result.flag_key == "test-flag" + assert result.rule_id == "rule1" + assert result.rule_type is not None assert result.reason != "" async def test_evaluates_flag_with_user_context(self, engine: RulesEngineClient) -> None: @@ -116,11 +121,13 @@ async def test_evaluates_flag_with_user_context(self, engine: RulesEngineClient) result = engine.check_flag(flag, None, user) assert isinstance(result, RulesengineCheckFlagResult) assert result.value is True + assert result.flag_key == "user-flag" async def test_returns_default_for_empty_rules(self, engine: RulesEngineClient) -> None: flag = _make_flag(id="flag3", key="empty-rules", default_value=False) result = engine.check_flag(flag) assert result.value is False + assert result.flag_key == "empty-rules" class TestRulesEngineFileNotFound: From bda38904ce09394c364694b4050a3ba688365de7 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 26 Mar 2026 10:00:31 -0600 Subject: [PATCH 14/19] make cache key more deterministic --- src/schematic/client.py | 9 ++++++--- tests/custom/test_cache_key.py | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/schematic/client.py b/src/schematic/client.py index 1ba9170..65d3b30 100644 --- a/src/schematic/client.py +++ b/src/schematic/client.py @@ -556,6 +556,9 @@ def _build_cache_key( company: Optional[Dict[str, str]] = None, user: Optional[Dict[str, str]] = None, ) -> str: - if company or user: - return flag_key + ":" + str(company) + ":" + str(user) - return flag_key + parts = [flag_key] + if company: + parts.append("company:" + ";".join(f"{k}={v}" for k, v in sorted(company.items()))) + if user: + parts.append("user:" + ";".join(f"{k}={v}" for k, v in sorted(user.items()))) + return ":".join(parts) diff --git a/tests/custom/test_cache_key.py b/tests/custom/test_cache_key.py index b933862..6fdae11 100644 --- a/tests/custom/test_cache_key.py +++ b/tests/custom/test_cache_key.py @@ -64,6 +64,27 @@ def test_same_context_produces_same_key(self): key2 = _build_cache_key("flag", company={"id": "comp-1"}, user={"id": "user-1"}) self.assertEqual(key1, key2) + def test_deterministic_regardless_of_insertion_order(self): + """Dict insertion order must not affect the cache key.""" + key1 = _build_cache_key("flag", company={"id": "comp-1", "name": "ACME"}) + key2 = _build_cache_key("flag", company={"name": "ACME", "id": "comp-1"}) + self.assertEqual(key1, key2) + + def test_deterministic_with_multiple_user_keys(self): + """Multiple user keys in different order produce the same cache key.""" + key1 = _build_cache_key("flag", user={"email": "a@b.com", "id": "u1", "phone": "555"}) + key2 = _build_cache_key("flag", user={"phone": "555", "email": "a@b.com", "id": "u1"}) + self.assertEqual(key1, key2) + + def test_exact_format(self): + """Verify the canonical cache key format.""" + result = _build_cache_key( + "my-flag", + company={"id": "co1"}, + user={"email": "a@b.com", "id": "u1"}, + ) + self.assertEqual(result, "my-flag:company:id=co1:user:email=a@b.com;id=u1") + if __name__ == "__main__": unittest.main() From 9a07bd09970165733271be7f0d5cf90c8d683a50 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 26 Mar 2026 10:24:41 -0600 Subject: [PATCH 15/19] optionally import websockets package --- .github/workflows/ci.yml | 4 ++-- README.md | 8 ++++---- poetry.lock | 12 +++++++----- pyproject.toml | 3 ++- src/schematic/datastream/rules_engine.py | 2 +- src/schematic/datastream/websocket_client.py | 11 +++++++++-- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80b9954..da75057 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Install dependencies - run: poetry install --extras rulesengine + run: poetry install --extras datastream - name: Compile run: poetry run mypy . test: @@ -30,7 +30,7 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Install dependencies - run: poetry install --extras rulesengine + run: poetry install --extras datastream - name: Test run: poetry run pytest -rP -n auto . diff --git a/README.md b/README.md index 787db32..687b62f 100644 --- a/README.md +++ b/README.md @@ -289,14 +289,14 @@ client.check_flag( The DataStream functionality provides real-time updates for flags, companies, and users. It uses WebSocket connections to receive updates from the Schematic backend and evaluates feature flags locally using a WASM rules engine, reducing the number of network calls. -### Requirements +### Installation -DataStream requires the `rulesengine` extra for local flag evaluation: +DataStream requires additional dependencies for WebSocket connections and local flag evaluation. Install them with the `datastream` extra: ```bash -pip install schematichq[rulesengine] +pip install 'schematichq[datastream]' # or -poetry add schematichq -E rulesengine +poetry add schematichq -E datastream ``` ### Key Features diff --git a/poetry.lock b/poetry.lock index ec1590f..107ce04 100644 --- a/poetry.lock +++ b/poetry.lock @@ -178,7 +178,7 @@ description = "Read resources from Python packages" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"rulesengine\"" +markers = "extra == \"datastream\" or extra == \"rulesengine\"" files = [ {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, @@ -654,7 +654,7 @@ description = "A WebAssembly runtime powered by Wasmtime" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"rulesengine\"" +markers = "extra == \"datastream\" or extra == \"rulesengine\"" files = [ {file = "wasmtime-25.0.0-py3-none-any.whl", hash = "sha256:22aa59fc6e01deec8a6703046f82466090d5811096a3bb5c169907e36c842af1"}, {file = "wasmtime-25.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:13e9a718e9d580c1738782cc19f4dcb9fb068f7e51778ea621fd664f4433525b"}, @@ -675,9 +675,10 @@ testing = ["componentize-py", "coverage", "pycparser", "pytest", "pytest-mypy"] name = "websockets" version = "13.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"datastream\"" files = [ {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, @@ -774,7 +775,7 @@ description = "Backport of pathlib-compatible object wrapper for zip files" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"rulesengine\" and python_version < \"3.10\"" +markers = "(extra == \"datastream\" or extra == \"rulesengine\") and python_version < \"3.10\"" files = [ {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, @@ -789,9 +790,10 @@ test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.funct type = ["pytest-mypy"] [extras] +datastream = ["wasmtime", "websockets"] rulesengine = ["wasmtime"] [metadata] lock-version = "2.1" python-versions = "^3.8" -content-hash = "fac28b41db959c73343ddaccefd13515de5f557e0eb8de7b2fa0f84ca98e96f6" +content-hash = "fe5ba1a2a6da427a37d4a3e628adbeb1f5a433ae8d8ba4c71d7b0b694c90b16c" diff --git a/pyproject.toml b/pyproject.toml index 1850ea4..8d9389c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,10 +41,11 @@ httpx = ">=0.21.2" pydantic = ">= 1.9.2" pydantic-core = ">=2.18.2" typing_extensions = ">= 4.0.0" -websockets = ">=10.0" +websockets = { version = ">=10.0", optional = true } wasmtime = { version = ">=19.0.0", optional = true } [tool.poetry.extras] +datastream = ["websockets", "wasmtime"] rulesengine = ["wasmtime"] [tool.poetry.group.dev.dependencies] diff --git a/src/schematic/datastream/rules_engine.py b/src/schematic/datastream/rules_engine.py index a4fde5b..e86520e 100644 --- a/src/schematic/datastream/rules_engine.py +++ b/src/schematic/datastream/rules_engine.py @@ -73,7 +73,7 @@ async def initialize(self) -> None: except ImportError: raise ImportError( "wasmtime is required for the rules engine. " - "Install it with: pip install 'schematichq[rulesengine]' or pip install wasmtime" + "Install it with: pip install 'schematichq[datastream]' or pip install wasmtime" ) if not self._wasm_path.exists(): diff --git a/src/schematic/datastream/websocket_client.py b/src/schematic/datastream/websocket_client.py index a817de0..c71387b 100644 --- a/src/schematic/datastream/websocket_client.py +++ b/src/schematic/datastream/websocket_client.py @@ -10,12 +10,14 @@ from typing import Any, Awaitable, Callable, Dict, Optional, Union from urllib.parse import urlparse, urlunparse -import websockets +try: + import websockets # type: ignore[import-untyped] +except ImportError: + websockets = None # type: ignore[assignment] from .types import DataStreamBaseReq, DataStreamResp - # Connection timing constants (seconds) WRITE_WAIT = 10.0 PONG_WAIT = 60.0 @@ -216,6 +218,11 @@ async def close(self) -> None: async def _connect_and_read(self) -> None: while self._should_reconnect: try: + if websockets is None: + raise ImportError( + "websockets is required for DataStream. " + "Install it with: pip install 'schematichq[datastream]'" + ) async with websockets.connect( self._url, additional_headers=self._headers, From ee560632f482e55d9464c9e5a42cc5cd2c0ef36e Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 26 Mar 2026 14:39:29 -0600 Subject: [PATCH 16/19] do not keep wasm files in git --- .fernignore | 1 + .github/workflows/ci.yml | 42 ++++++++++- .gitignore | 4 ++ WASM_VERSION | 1 + scripts/download-wasm.sh | 66 ++++++++++++++++++ .../datastream/wasm/rulesengine.wasm | Bin 577191 -> 0 bytes 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 WASM_VERSION create mode 100755 scripts/download-wasm.sh delete mode 100755 src/schematic/datastream/wasm/rulesengine.wasm diff --git a/.fernignore b/.fernignore index c60cef2..a2a4fc3 100644 --- a/.fernignore +++ b/.fernignore @@ -21,3 +21,4 @@ tests/custom/ tests/datastream/ tests/webhook_utils/ CLAUDE.md +WASM_VERSION diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da75057..8f630ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ jobs: - name: Bootstrap poetry run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Download WASM binary + run: ./scripts/download-wasm.sh + env: + GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install --extras datastream - name: Compile @@ -29,14 +33,46 @@ jobs: - name: Bootstrap poetry run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Download WASM binary + run: ./scripts/download-wasm.sh + env: + GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install --extras datastream - name: Test run: poetry run pytest -rP -n auto . + verify-package: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Download WASM binary + run: ./scripts/download-wasm.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Build package + run: poetry build + - name: Verify WASM in wheel + run: | + if ! zipinfo dist/*.whl | grep -q 'rulesengine.wasm'; then + echo "ERROR: rulesengine.wasm not found in wheel" + echo "Wheel contents:" + zipinfo dist/*.whl + exit 1 + fi + echo "Verified: rulesengine.wasm is included in the wheel" + publish: - needs: [compile, test] + needs: [compile, test, verify-package] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: @@ -49,6 +85,10 @@ jobs: - name: Bootstrap poetry run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Download WASM binary + run: ./scripts/download-wasm.sh + env: + GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install - name: Publish to pypi diff --git a/.gitignore b/.gitignore index d2e4ca8..9c767ac 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ __pycache__/ dist/ poetry.toml + +# WASM binary (downloaded from rulesengine-rust GitHub Releases) +src/schematic/datastream/wasm/rulesengine.wasm +src/schematic/datastream/wasm/.wasm_version diff --git a/WASM_VERSION b/WASM_VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/WASM_VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/scripts/download-wasm.sh b/scripts/download-wasm.sh new file mode 100755 index 0000000..24e8c52 --- /dev/null +++ b/scripts/download-wasm.sh @@ -0,0 +1,66 @@ +#!/bin/bash +set -e + +# Downloads the rules engine WASM binary from the schematic-api GitHub Release. +# Reads the pinned version from WASM_VERSION at the repo root. + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +WASM_DIR="$REPO_ROOT/src/schematic/datastream/wasm" +VERSION_FILE="$REPO_ROOT/WASM_VERSION" +TARGET_FILE="$WASM_DIR/rulesengine.wasm" + +GITHUB_REPO="SchematicHQ/schematic-api" + +if [ ! -f "$VERSION_FILE" ]; then + echo "ERROR: WASM_VERSION file not found at $VERSION_FILE" + exit 1 +fi + +VERSION=$(tr -d '[:space:]' < "$VERSION_FILE") +TAG="rulesengine/v${VERSION}" + +# Skip download if binary already exists and version matches +if [ -f "$TARGET_FILE" ] && [ -f "$WASM_DIR/.wasm_version" ]; then + CURRENT=$(tr -d '[:space:]' < "$WASM_DIR/.wasm_version") + if [ "$CURRENT" = "$VERSION" ]; then + echo "WASM binary already at version $VERSION, skipping download." + exit 0 + fi +fi + +ASSET_NAME="rulesengine-wasm-python-v${VERSION}.tar.gz" + +echo "Downloading rules engine WASM v${VERSION}..." +mkdir -p "$WASM_DIR" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +if ! gh release download "$TAG" \ + -R "$GITHUB_REPO" \ + -p "$ASSET_NAME" \ + -D "$TMPDIR" 2>/dev/null; then + echo "ERROR: Failed to download WASM binary" + echo "Tag: $TAG" + echo "Asset: $ASSET_NAME" + echo "" + echo "If this is a new version, ensure a release exists at:" + echo " https://github.com/${GITHUB_REPO}/releases/tag/${TAG}" + echo "" + echo "Ensure the GitHub CLI is authenticated: gh auth status" + exit 1 +fi + +tar -xzf "$TMPDIR/$ASSET_NAME" -C "$TMPDIR" + +if [ ! -f "$TMPDIR/rulesengine.wasm" ]; then + echo "ERROR: rulesengine.wasm not found in release archive" + ls -la "$TMPDIR" + exit 1 +fi + +cp "$TMPDIR/rulesengine.wasm" "$TARGET_FILE" +echo "$VERSION" > "$WASM_DIR/.wasm_version" + +echo "Downloaded rules engine WASM v${VERSION} to $TARGET_FILE" diff --git a/src/schematic/datastream/wasm/rulesengine.wasm b/src/schematic/datastream/wasm/rulesengine.wasm deleted file mode 100755 index a5c7a5a5ca1920972b161cf7f303a48bfbfad3fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 577191 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 JlepTZe#`BN-Abrmx|ApLr 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

WNl+I=?r8PD&{^98-)Hgqa2=zVJP+8@-pdcv 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%0Dx5T`yPOMr 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 AssI20 From aa0706e642ffdb28ce8c72eb2ed03a5fb25a7314 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Fri, 27 Mar 2026 09:24:39 -0600 Subject: [PATCH 17/19] use correct token --- .github/workflows/ci.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f630ff..8baf77a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,7 @@ name: ci on: [push] +env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} jobs: compile: runs-on: ubuntu-latest @@ -15,8 +17,6 @@ jobs: curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Download WASM binary run: ./scripts/download-wasm.sh - env: - GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install --extras datastream - name: Compile @@ -35,8 +35,6 @@ jobs: curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Download WASM binary run: ./scripts/download-wasm.sh - env: - GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install --extras datastream @@ -57,8 +55,6 @@ jobs: curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Download WASM binary run: ./scripts/download-wasm.sh - env: - GH_TOKEN: ${{ github.token }} - name: Build package run: poetry build - name: Verify WASM in wheel @@ -87,8 +83,6 @@ jobs: curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Download WASM binary run: ./scripts/download-wasm.sh - env: - GH_TOKEN: ${{ github.token }} - name: Install dependencies run: poetry install - name: Publish to pypi From ae42b8dce5955e676a35bc147a7861318af3b268 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Fri, 27 Mar 2026 09:33:29 -0600 Subject: [PATCH 18/19] add wasm files to wheel --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8d9389c..1fa35ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,10 @@ packages = [ { include = "schematic", from = "src"} ] +include = [ + { path = "src/schematic/datastream/wasm/*.wasm", format = ["sdist", "wheel"] } +] + [tool.poetry.urls] Repository = 'https://github.com/schematichq/schematic-python' From 5b858777364def7c32ea937bfa0c8e409ee4e275 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Fri, 27 Mar 2026 10:00:27 -0600 Subject: [PATCH 19/19] standardize no ttl --- README.md | 6 +++--- src/schematic/datastream/datastream_client.py | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 687b62f..17070ee 100644 --- a/README.md +++ b/README.md @@ -368,7 +368,7 @@ asyncio.run(main()) #### Cache TTL Configuration -When using Replicator Mode, you should set the SDK's cache TTL to match the replicator's cache TTL. The replicator defaults to an unlimited cache TTL (`0`). If the SDK uses a shorter TTL (the default is 24 hours), locally updated cache entries will be written back with the shorter TTL and eventually evicted from the shared cache. +When using Replicator Mode, you should set the SDK's cache TTL to match the replicator's cache TTL. The replicator defaults to an unlimited cache TTL. If the SDK uses a shorter TTL (the default is 24 hours), locally updated cache entries will be written back with the shorter TTL and eventually evicted from the shared cache. To match the replicator's default unlimited TTL: @@ -377,7 +377,7 @@ config = AsyncSchematicConfig( use_datastream=True, datastream=DataStreamConfig( replicator_mode=True, - cache_ttl=0, # Unlimited, matching the replicator default + cache_ttl=None, # Unlimited, matching the replicator default ), ) ``` @@ -389,7 +389,7 @@ config = AsyncSchematicConfig( use_datastream=True, datastream=DataStreamConfig( replicator_mode=True, - cache_ttl=0, + cache_ttl=None, replicator_health_url="http://my-replicator:8090/ready", replicator_health_check=60_000, # 60 seconds, in milliseconds ), diff --git a/src/schematic/datastream/datastream_client.py b/src/schematic/datastream/datastream_client.py index abcac0e..28ca895 100644 --- a/src/schematic/datastream/datastream_client.py +++ b/src/schematic/datastream/datastream_client.py @@ -88,7 +88,7 @@ class DataStreamClientOptions: api_key: str logger: logging.Logger base_url: Optional[str] = None - cache_ttl: int = DEFAULT_TTL_MS + cache_ttl: Optional[int] = DEFAULT_TTL_MS # Custom cache providers (override defaults) company_cache: Optional[AsyncCacheProvider[Any]] = None @@ -174,14 +174,15 @@ def __init__(self, options: DataStreamClientOptions) -> None: ) # Cache providers - flag_ttl = max(MAX_CACHE_TTL_MS, self._cache_ttl) - self._company_cache: AsyncCacheProvider[RulesengineCompany] = options.company_cache or AsyncLocalCache(ttl=self._cache_ttl) - self._user_cache: AsyncCacheProvider[RulesengineUser] = options.user_cache or AsyncLocalCache(ttl=self._cache_ttl) + local_ttl = self._cache_ttl if self._cache_ttl is not None else DEFAULT_TTL_MS + flag_ttl = max(MAX_CACHE_TTL_MS, local_ttl) + self._company_cache: AsyncCacheProvider[RulesengineCompany] = options.company_cache or AsyncLocalCache(ttl=local_ttl) + self._user_cache: AsyncCacheProvider[RulesengineUser] = options.user_cache or AsyncLocalCache(ttl=local_ttl) self._flag_cache: AsyncCacheProvider[RulesengineFlag] = options.flag_cache or AsyncLocalCache(ttl=flag_ttl) # Key -> ID mapping caches (two-level caching) - self._company_key_cache: AsyncCacheProvider[str] = options.company_lookup_cache or AsyncLocalCache(ttl=self._cache_ttl) - self._user_key_cache: AsyncCacheProvider[str] = options.user_lookup_cache or AsyncLocalCache(ttl=self._cache_ttl) + self._company_key_cache: AsyncCacheProvider[str] = options.company_lookup_cache or AsyncLocalCache(ttl=local_ttl) + self._user_key_cache: AsyncCacheProvider[str] = options.user_lookup_cache or AsyncLocalCache(ttl=local_ttl) # WebSocket client self._ws_client: Optional[DatastreamWSClient] = None