hgraph-fabric 0.8.20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hgraph_fabric-0.8.20/CHANGELOG.md +34 -0
- hgraph_fabric-0.8.20/CMakeLists.txt +184 -0
- hgraph_fabric-0.8.20/LICENSE +21 -0
- hgraph_fabric-0.8.20/PKG-INFO +347 -0
- hgraph_fabric-0.8.20/README.md +333 -0
- hgraph_fabric-0.8.20/cmake/hgraph-fabricConfig.cmake.in +12 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/config.h +61 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/export.h +23 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/fabric.h +17 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/history.h +25 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/kafka.h +44 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/kafka_export.h +16 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/keys.h +52 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/metadata_codec.h +87 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/notifier.h +152 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/operators.h +108 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/planning.h +80 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/publication.h +109 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/resolution.h +241 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/service.h +180 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/types.h +105 -0
- hgraph_fabric-0.8.20/include/hgraph/fabric/value_builders.h +28 -0
- hgraph_fabric-0.8.20/pyproject.toml +51 -0
- hgraph_fabric-0.8.20/python/examples/README.md +42 -0
- hgraph_fabric-0.8.20/python/examples/derived_dataset.py +86 -0
- hgraph_fabric-0.8.20/python/examples/load_data.py +39 -0
- hgraph_fabric-0.8.20/python/examples/publish_once.py +38 -0
- hgraph_fabric-0.8.20/python/examples/subscription_modes.py +31 -0
- hgraph_fabric-0.8.20/python/hgraph_fabric/__init__.py +279 -0
- hgraph_fabric-0.8.20/python/hgraph_fabric/py.typed +1 -0
- hgraph_fabric-0.8.20/python/tests/test_distribution_audit.py +65 -0
- hgraph_fabric-0.8.20/python/tests/test_examples.py +43 -0
- hgraph_fabric-0.8.20/python/tests/test_public_contracts.py +346 -0
- hgraph_fabric-0.8.20/python/tests/test_resolution.py +120 -0
- hgraph_fabric-0.8.20/src/config.cpp +126 -0
- hgraph_fabric-0.8.20/src/history.cpp +106 -0
- hgraph_fabric-0.8.20/src/impl/memory_notifier.cpp +141 -0
- hgraph_fabric-0.8.20/src/impl/metadata_binding.h +179 -0
- hgraph_fabric-0.8.20/src/impl/metadata_value_binding.h +49 -0
- hgraph_fabric-0.8.20/src/impl/service_state.h +332 -0
- hgraph_fabric-0.8.20/src/kafka.cpp +350 -0
- hgraph_fabric-0.8.20/src/keys.cpp +138 -0
- hgraph_fabric-0.8.20/src/metadata_codec.cpp +139 -0
- hgraph_fabric-0.8.20/src/notifier.cpp +229 -0
- hgraph_fabric-0.8.20/src/operators.cpp +715 -0
- hgraph_fabric-0.8.20/src/planning.cpp +246 -0
- hgraph_fabric-0.8.20/src/publication.cpp +567 -0
- hgraph_fabric-0.8.20/src/python_module.cpp +368 -0
- hgraph_fabric-0.8.20/src/resolution.cpp +1020 -0
- hgraph_fabric-0.8.20/src/service.cpp +1471 -0
- hgraph_fabric-0.8.20/src/subscription.cpp +1146 -0
- hgraph_fabric-0.8.20/src/types.cpp +121 -0
- hgraph_fabric-0.8.20/src/value_builders.cpp +279 -0
- hgraph_fabric-0.8.20/test_package/CMakeLists.txt +28 -0
- hgraph_fabric-0.8.20/test_package/check.py +120 -0
- hgraph_fabric-0.8.20/test_package/main.cpp +139 -0
- hgraph_fabric-0.8.20/tests/CMakeLists.txt +44 -0
- hgraph_fabric-0.8.20/tests/registry_test_listener.cpp +32 -0
- hgraph_fabric-0.8.20/tests/resolution_perf.cpp +372 -0
- hgraph_fabric-0.8.20/tests/test_backends.cpp +350 -0
- hgraph_fabric-0.8.20/tests/test_history.cpp +130 -0
- hgraph_fabric-0.8.20/tests/test_kafka.cpp +839 -0
- hgraph_fabric-0.8.20/tests/test_public_contracts.cpp +718 -0
- hgraph_fabric-0.8.20/tests/test_publication.cpp +720 -0
- hgraph_fabric-0.8.20/tests/test_resolution.cpp +362 -0
- hgraph_fabric-0.8.20/tests/test_subscription.cpp +1383 -0
- hgraph_fabric-0.8.20/tools/audit_distribution.py +205 -0
- hgraph_fabric-0.8.20/tools/run_kafka_broker_conformance.py +181 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- Keep complete revisions in `Shared<DataRevision>` from Kafka decode through
|
|
6
|
+
Fabric notice admission and graph-transport retry; retain notification
|
|
7
|
+
candidates, correlation, retry and completion on explicit graph edges; create
|
|
8
|
+
mutable Fabric algorithm state in each owning node and Kafka I/O resources
|
|
9
|
+
per `GraphValue`; and retain only live notices known to an active consistency
|
|
10
|
+
forest.
|
|
11
|
+
- Scaffold the RFC 0026 extension and its installed public C++/Python contracts.
|
|
12
|
+
- Add canonical revision/reference metadata encoding and the memory notifier.
|
|
13
|
+
- Add canonical durable keys and the resumable, acknowledgement-gated
|
|
14
|
+
publication state machine with schema locking and crash/index repair.
|
|
15
|
+
- Add the native wiring-time dependency planner, explicit subscription handles,
|
|
16
|
+
independent consistency forests, and hidden publisher lineage cuts.
|
|
17
|
+
- Add the shared root Fabric service, run-selected Replay/Live subscription
|
|
18
|
+
sessions, service-owned publication and version-load paths, a standalone
|
|
19
|
+
as-of point lookup, complete-revision live cache ingestion, and the local
|
|
20
|
+
Python memory-service host.
|
|
21
|
+
- Add the optional graph-native Kafka transport: strict Fabric producer/queue
|
|
22
|
+
profiles, full accepted-revision payloads, root push-source ingress through
|
|
23
|
+
the Kafka service, lifecycle-gated durable handoff, explicit cursor commits,
|
|
24
|
+
graph-owned correlated bounded delivery retry, and transport diagnostics.
|
|
25
|
+
- Add local/S3 and Arrow IPC/Parquet behavior coverage, a cross-process
|
|
26
|
+
publication race, resolver/cache and bounded-queue diagnostics, service
|
|
27
|
+
lifecycle logs, installed wheel SDK consumers, dependency-first Windows DLL
|
|
28
|
+
setup, release artifacts, and production operating guidance.
|
|
29
|
+
- Add restartable real-broker conformance for startup handoff, retriable
|
|
30
|
+
delivery failure, reconnect recovery, bounded queue profiles, and keyed
|
|
31
|
+
partition ordering.
|
|
32
|
+
- Add typed, path-addressed transport/store event diagnostics and executable
|
|
33
|
+
hard-bound coverage for stalled publication, live-notice, and diagnostic
|
|
34
|
+
queues.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.25)
|
|
2
|
+
|
|
3
|
+
project(hgraph_fabric VERSION 0.8.0 LANGUAGES CXX)
|
|
4
|
+
|
|
5
|
+
include(GNUInstallDirs)
|
|
6
|
+
include(CMakePackageConfigHelpers)
|
|
7
|
+
include(CTest)
|
|
8
|
+
|
|
9
|
+
option(HGRAPH_FABRIC_BUILD_PYTHON "Build the optional Python authoring bridge" OFF)
|
|
10
|
+
option(HGRAPH_FABRIC_WARNINGS_AS_ERRORS
|
|
11
|
+
"Treat hgraph-fabric compiler warnings as errors"
|
|
12
|
+
${HGRAPH_WARNINGS_AS_ERRORS})
|
|
13
|
+
|
|
14
|
+
set(_hgraph_fabric_kafka_default OFF)
|
|
15
|
+
if(TARGET hgraph::kafka)
|
|
16
|
+
set(_hgraph_fabric_kafka_default ON)
|
|
17
|
+
endif()
|
|
18
|
+
option(HGRAPH_FABRIC_BUILD_KAFKA
|
|
19
|
+
"Build the optional graph-native Kafka transport adapter"
|
|
20
|
+
${_hgraph_fabric_kafka_default})
|
|
21
|
+
|
|
22
|
+
if(HGRAPH_FABRIC_BUILD_PYTHON)
|
|
23
|
+
find_package(Python 3.12 COMPONENTS
|
|
24
|
+
Interpreter Development.Module Development.SABIModule REQUIRED)
|
|
25
|
+
endif()
|
|
26
|
+
|
|
27
|
+
if(NOT TARGET hgraph::core)
|
|
28
|
+
find_package(hgraph CONFIG REQUIRED)
|
|
29
|
+
endif()
|
|
30
|
+
if(NOT TARGET hgraph::persistence)
|
|
31
|
+
find_package(hgraph-persistence CONFIG REQUIRED)
|
|
32
|
+
endif()
|
|
33
|
+
|
|
34
|
+
add_library(hgraph_fabric
|
|
35
|
+
src/config.cpp
|
|
36
|
+
src/history.cpp
|
|
37
|
+
src/keys.cpp
|
|
38
|
+
src/metadata_codec.cpp
|
|
39
|
+
src/notifier.cpp
|
|
40
|
+
src/operators.cpp
|
|
41
|
+
src/planning.cpp
|
|
42
|
+
src/publication.cpp
|
|
43
|
+
src/resolution.cpp
|
|
44
|
+
src/service.cpp
|
|
45
|
+
src/subscription.cpp
|
|
46
|
+
src/types.cpp
|
|
47
|
+
src/value_builders.cpp
|
|
48
|
+
src/impl/memory_notifier.cpp
|
|
49
|
+
)
|
|
50
|
+
add_library(hgraph::fabric ALIAS hgraph_fabric)
|
|
51
|
+
|
|
52
|
+
get_target_property(HGRAPH_FABRIC_LIBRARY_TYPE hgraph_fabric TYPE)
|
|
53
|
+
if(HGRAPH_FABRIC_LIBRARY_TYPE STREQUAL "STATIC_LIBRARY")
|
|
54
|
+
target_compile_definitions(hgraph_fabric PUBLIC HGRAPH_FABRIC_STATIC_DEFINE)
|
|
55
|
+
endif()
|
|
56
|
+
|
|
57
|
+
target_compile_features(hgraph_fabric PUBLIC cxx_std_23)
|
|
58
|
+
target_link_libraries(hgraph_fabric PUBLIC hgraph::core hgraph::persistence)
|
|
59
|
+
target_include_directories(hgraph_fabric
|
|
60
|
+
PUBLIC
|
|
61
|
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
62
|
+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
63
|
+
)
|
|
64
|
+
set_target_properties(hgraph_fabric PROPERTIES
|
|
65
|
+
EXPORT_NAME fabric
|
|
66
|
+
POSITION_INDEPENDENT_CODE ON
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if(HGRAPH_FABRIC_BUILD_KAFKA)
|
|
70
|
+
if(NOT TARGET hgraph::kafka)
|
|
71
|
+
find_package(hgraph-kafka CONFIG REQUIRED)
|
|
72
|
+
endif()
|
|
73
|
+
add_library(hgraph_fabric_kafka src/kafka.cpp)
|
|
74
|
+
add_library(hgraph::fabric_kafka ALIAS hgraph_fabric_kafka)
|
|
75
|
+
get_target_property(HGRAPH_FABRIC_KAFKA_LIBRARY_TYPE hgraph_fabric_kafka TYPE)
|
|
76
|
+
if(HGRAPH_FABRIC_KAFKA_LIBRARY_TYPE STREQUAL "STATIC_LIBRARY")
|
|
77
|
+
target_compile_definitions(hgraph_fabric_kafka PUBLIC HGRAPH_FABRIC_KAFKA_STATIC_DEFINE)
|
|
78
|
+
endif()
|
|
79
|
+
target_compile_features(hgraph_fabric_kafka PUBLIC cxx_std_23)
|
|
80
|
+
target_link_libraries(hgraph_fabric_kafka PUBLIC hgraph::fabric hgraph::kafka)
|
|
81
|
+
target_include_directories(hgraph_fabric_kafka
|
|
82
|
+
PUBLIC
|
|
83
|
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
84
|
+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
85
|
+
)
|
|
86
|
+
set_target_properties(hgraph_fabric_kafka PROPERTIES
|
|
87
|
+
EXPORT_NAME fabric_kafka
|
|
88
|
+
POSITION_INDEPENDENT_CODE ON
|
|
89
|
+
)
|
|
90
|
+
if(MSVC)
|
|
91
|
+
target_compile_options(hgraph_fabric_kafka PRIVATE /W4 /permissive-)
|
|
92
|
+
if(HGRAPH_FABRIC_WARNINGS_AS_ERRORS)
|
|
93
|
+
target_compile_options(hgraph_fabric_kafka PRIVATE /WX)
|
|
94
|
+
endif()
|
|
95
|
+
else()
|
|
96
|
+
target_compile_options(hgraph_fabric_kafka PRIVATE -Wall -Wextra -Wpedantic)
|
|
97
|
+
if(HGRAPH_FABRIC_WARNINGS_AS_ERRORS)
|
|
98
|
+
target_compile_options(hgraph_fabric_kafka PRIVATE -Werror)
|
|
99
|
+
endif()
|
|
100
|
+
endif()
|
|
101
|
+
endif()
|
|
102
|
+
|
|
103
|
+
if(MSVC)
|
|
104
|
+
# Class exports are producer-only; private STL representation is not
|
|
105
|
+
# imported by consumers. Scope these interface diagnostics to this DLL.
|
|
106
|
+
target_compile_options(hgraph_fabric PRIVATE
|
|
107
|
+
/W4 /permissive- /wd4251 /wd4275)
|
|
108
|
+
if(HGRAPH_FABRIC_WARNINGS_AS_ERRORS)
|
|
109
|
+
target_compile_options(hgraph_fabric PRIVATE /WX)
|
|
110
|
+
endif()
|
|
111
|
+
else()
|
|
112
|
+
target_compile_options(hgraph_fabric PRIVATE -Wall -Wextra -Wpedantic)
|
|
113
|
+
if(HGRAPH_FABRIC_WARNINGS_AS_ERRORS)
|
|
114
|
+
target_compile_options(hgraph_fabric PRIVATE -Werror)
|
|
115
|
+
endif()
|
|
116
|
+
endif()
|
|
117
|
+
|
|
118
|
+
if(BUILD_TESTING)
|
|
119
|
+
add_subdirectory(tests)
|
|
120
|
+
endif()
|
|
121
|
+
|
|
122
|
+
if(HGRAPH_FABRIC_BUILD_PYTHON)
|
|
123
|
+
if(NOT COMMAND hgraph_add_python_module OR NOT TARGET hgraph::nanobind)
|
|
124
|
+
message(FATAL_ERROR
|
|
125
|
+
"HGRAPH_FABRIC_BUILD_PYTHON requires a Python-enabled installed hgraph SDK")
|
|
126
|
+
endif()
|
|
127
|
+
hgraph_add_python_module(_hgraph_fabric STABLE_ABI NOMINSIZE src/python_module.cpp)
|
|
128
|
+
target_link_libraries(_hgraph_fabric PRIVATE hgraph::fabric)
|
|
129
|
+
if(APPLE)
|
|
130
|
+
set_target_properties(_hgraph_fabric PROPERTIES
|
|
131
|
+
INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path/../pyarrow")
|
|
132
|
+
elseif(UNIX)
|
|
133
|
+
set_target_properties(_hgraph_fabric PROPERTIES
|
|
134
|
+
INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR};$ORIGIN/../pyarrow")
|
|
135
|
+
endif()
|
|
136
|
+
install(TARGETS _hgraph_fabric
|
|
137
|
+
COMPONENT Python
|
|
138
|
+
LIBRARY DESTINATION hgraph_fabric
|
|
139
|
+
RUNTIME DESTINATION hgraph_fabric
|
|
140
|
+
)
|
|
141
|
+
endif()
|
|
142
|
+
|
|
143
|
+
install(TARGETS hgraph_fabric
|
|
144
|
+
EXPORT hgraphFabricTargets
|
|
145
|
+
COMPONENT Development
|
|
146
|
+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
147
|
+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
148
|
+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
149
|
+
)
|
|
150
|
+
if(TARGET hgraph_fabric_kafka)
|
|
151
|
+
install(TARGETS hgraph_fabric_kafka
|
|
152
|
+
EXPORT hgraphFabricTargets
|
|
153
|
+
COMPONENT Development
|
|
154
|
+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
155
|
+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
156
|
+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
157
|
+
)
|
|
158
|
+
endif()
|
|
159
|
+
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
|
160
|
+
COMPONENT Development FILES_MATCHING PATTERN "*.h")
|
|
161
|
+
|
|
162
|
+
write_basic_package_version_file(
|
|
163
|
+
"${PROJECT_BINARY_DIR}/hgraph-fabricConfigVersion.cmake"
|
|
164
|
+
VERSION ${PROJECT_VERSION}
|
|
165
|
+
COMPATIBILITY SameMajorVersion
|
|
166
|
+
)
|
|
167
|
+
configure_package_config_file(
|
|
168
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/hgraph-fabricConfig.cmake.in"
|
|
169
|
+
"${PROJECT_BINARY_DIR}/hgraph-fabricConfig.cmake"
|
|
170
|
+
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-fabric
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
install(EXPORT hgraphFabricTargets
|
|
174
|
+
FILE hgraphFabricTargets.cmake
|
|
175
|
+
NAMESPACE hgraph::
|
|
176
|
+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-fabric
|
|
177
|
+
COMPONENT Development
|
|
178
|
+
)
|
|
179
|
+
install(FILES
|
|
180
|
+
"${PROJECT_BINARY_DIR}/hgraph-fabricConfig.cmake"
|
|
181
|
+
"${PROJECT_BINARY_DIR}/hgraph-fabricConfigVersion.cmake"
|
|
182
|
+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-fabric
|
|
183
|
+
COMPONENT Development
|
|
184
|
+
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Howard Henson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: hgraph-fabric
|
|
3
|
+
Version: 0.8.20
|
|
4
|
+
Summary: Versioned dataflow fabric for recurring hgraph computations
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/hhenson/hgraph
|
|
7
|
+
Project-URL: Repository, https://github.com/hhenson/hgraph.git
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: hgraph>=0.8.0
|
|
10
|
+
Requires-Dist: hgraph-persistence>=0.8.0
|
|
11
|
+
Provides-Extra: test
|
|
12
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# hgraph-fabric
|
|
16
|
+
|
|
17
|
+
`hgraph-fabric` is the C++-first versioned dataflow extension specified by
|
|
18
|
+
[RFC 0026](../../docs/source/rfc/rfc_0026_versioned_dataflow_fabric.rst).
|
|
19
|
+
It decouples recurring graph components through immutable, complete `Frame`
|
|
20
|
+
versions and contiguous lineage revisions.
|
|
21
|
+
|
|
22
|
+
The current implementation provides the installed C++/Python operator and
|
|
23
|
+
value contracts, canonical durable keys and metadata, run-scoped
|
|
24
|
+
configuration, and broker-free memory notification. One lazy root
|
|
25
|
+
`FabricServiceImpl` graph composes publication, live, replay, version load and
|
|
26
|
+
diagnostics nodes for each `GraphValue`. Each node owns only its local
|
|
27
|
+
algorithm state; their sequencing, candidates, completions, metrics and events
|
|
28
|
+
remain on ordinary graph edges. Persistence handles are copied from the
|
|
29
|
+
run-scoped `FabricConfig`. Client
|
|
30
|
+
`subscribe_data` and `publish_data` operators only communicate with that
|
|
31
|
+
service through hgraph service edges.
|
|
32
|
+
|
|
33
|
+
The native publication state machine writes each Frame, wins the immutable
|
|
34
|
+
revision slot, repairs the derived as-of/latest indexes, and only then
|
|
35
|
+
advertises the accepted revision. Notifier failure leaves the accepted
|
|
36
|
+
revision pending delivery so retry cannot change the durable winner. The
|
|
37
|
+
wiring-time planner discovers subscriptions through direct and nested graph
|
|
38
|
+
ownership, validates explicit dependency handles, partitions independent
|
|
39
|
+
consistency forests, and wires hidden lineage signals to publication requests.
|
|
40
|
+
|
|
41
|
+
The shared ingress coordinator derives behavior from the graph run:
|
|
42
|
+
|
|
43
|
+
* simulation walks durable as-of histories over the executor's half-open
|
|
44
|
+
interval using ordinary node scheduling; and
|
|
45
|
+
* real-time execution loads a durable initial image, then advances only when
|
|
46
|
+
a complete shared revision arrives on the ordinary notice edge.
|
|
47
|
+
|
|
48
|
+
There is no per-subscription mode. A narrow simulation interval provides the
|
|
49
|
+
graph-coordinated equivalent of a one-point replay. The separate synchronous
|
|
50
|
+
`load_data` API handles a simple single-dataset point lookup without
|
|
51
|
+
constructing or solving a consistency forest.
|
|
52
|
+
|
|
53
|
+
Complete live revision messages populate dependency indexes directly. Durable
|
|
54
|
+
metadata is read for startup, reconnect reconciliation and explicit revision
|
|
55
|
+
gaps; only a selected changed root causes its Frame to load. The live cache
|
|
56
|
+
retains only ids in the observed consistency forest, conflates by data id and
|
|
57
|
+
is bounded.
|
|
58
|
+
|
|
59
|
+
The optional `hgraph::fabric_kafka` target supplies the production transport.
|
|
60
|
+
It validates idempotent `acks=all` publication and non-dropping queue policies,
|
|
61
|
+
subscribes independently to the complete configured topic, and carries the
|
|
62
|
+
full accepted `DataRevision` keyed by canonical data id. Decoded Kafka records
|
|
63
|
+
and revisions cross their public C++ graph edges as immutable `Shared` values.
|
|
64
|
+
The Kafka service creates one execution-local broker worker resource. Its
|
|
65
|
+
standard burst push source emits ordinary graph
|
|
66
|
+
edges into Fabric; broker callbacks never access the graph or a Fabric output.
|
|
67
|
+
`Recovering` and `Live` lifecycle edges gate the initial durable image and
|
|
68
|
+
trigger durable-head reconciliation for each new live generation. Replay and
|
|
69
|
+
other simulation runs do not compose the adapter and never create a push source.
|
|
70
|
+
|
|
71
|
+
Publication crosses a graph-native request edge only after its Frame, immutable
|
|
72
|
+
revision and derived indexes are durable. The Fabric service graph retains
|
|
73
|
+
durable candidates in a keyed time series, serialises them onto one ordered
|
|
74
|
+
request edge, and correlates Kafka delivery reports returning on a separate
|
|
75
|
+
graph edge. Retriable failures unbind and rebind a reference to the same
|
|
76
|
+
``Shared<DataRevision>`` allocation. Candidate selection, retry, completion and
|
|
77
|
+
diagnostics remain graph-owned; acknowledgement never selects or creates a
|
|
78
|
+
revision. The Kafka worker owns only broker I/O, returning events through its
|
|
79
|
+
FIFO root push source. Valid decoded subscription cursors are explicitly
|
|
80
|
+
committed, but offsets remain non-authoritative because durable history repairs
|
|
81
|
+
duplicates or missed notifications.
|
|
82
|
+
|
|
83
|
+
Durable keys use a canonical reversible data-id segment and a portable
|
|
84
|
+
1,024-byte whole-key limit shared with S3. The fabric prefix and encoded data
|
|
85
|
+
id must leave room for the key category and fixed-width ordinal, which is
|
|
86
|
+
padded so a prefix listing returns revisions in order.
|
|
87
|
+
|
|
88
|
+
Metadata is a declared value schema written through
|
|
89
|
+
`persistence::store::ValueStore`, in that store's configured codec — `json` by
|
|
90
|
+
default. A stored revision is therefore an ordinary json document: it opens in
|
|
91
|
+
a text editor and any tool can read it. Fabric owns the schemas, the key
|
|
92
|
+
layout, and the check that an as-of entry is not read as a latest entry; it
|
|
93
|
+
owns no serialisation format.
|
|
94
|
+
|
|
95
|
+
Native hosts install `FabricConfig` in `GlobalState`, call
|
|
96
|
+
`hgraph::fabric::register_service()`, call
|
|
97
|
+
`hgraph::fabric::register_fabric_operators()`, and link `hgraph::fabric`.
|
|
98
|
+
Production Kafka hosts instead link `hgraph::fabric_kafka` and call
|
|
99
|
+
`hgraph::fabric::register_kafka_transport()` with the topic, stable identity
|
|
100
|
+
and `KafkaServiceConfig`; that call registers both lazy service singletons.
|
|
101
|
+
Python consumers import `hgraph_fabric` and call
|
|
102
|
+
`register_memory_fabric_service()` for the deterministic local host; importing
|
|
103
|
+
the package registers the same native operators.
|
|
104
|
+
|
|
105
|
+
## Python examples
|
|
106
|
+
|
|
107
|
+
Install the extension and import ordinary hgraph graph-building primitives:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
python -m pip install hgraph-fabric
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Fabric registration belongs in the outer host graph. Reusable components call
|
|
114
|
+
only `subscribe_data()` and `publish_data()`, so the same component can run
|
|
115
|
+
against the local memory host or a production host configured with persistent
|
|
116
|
+
stores and Kafka.
|
|
117
|
+
|
|
118
|
+
### Publish one Frame locally
|
|
119
|
+
|
|
120
|
+
This complete example publishes one atomic Arrow table. The memory service is
|
|
121
|
+
run-scoped and intended for local development and tests; a separate graph run
|
|
122
|
+
gets a separate memory Fabric.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from datetime import timedelta
|
|
126
|
+
|
|
127
|
+
import pyarrow as pa
|
|
128
|
+
import hgraph as hg
|
|
129
|
+
import hgraph_fabric as fabric
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@hg.graph
|
|
133
|
+
def publish_prices() -> None:
|
|
134
|
+
prices = hg.const(
|
|
135
|
+
pa.table({"symbol": ["AAPL", "MSFT"], "price": [201.5, 415.0]}),
|
|
136
|
+
tp=hg.TS[hg.Frame],
|
|
137
|
+
)
|
|
138
|
+
fabric.publish_data("prices/raw", prices)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@hg.graph
|
|
142
|
+
def local_app() -> None:
|
|
143
|
+
fabric.register_memory_fabric_service(prefix="examples/basic")
|
|
144
|
+
publish_prices()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
hg.run_graph(
|
|
148
|
+
local_app,
|
|
149
|
+
run_mode=hg.EvaluationMode.SIMULATION,
|
|
150
|
+
start_time=hg.MIN_ST,
|
|
151
|
+
end_time=hg.MIN_ST + timedelta(microseconds=20),
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The runnable version is
|
|
156
|
+
[`python/examples/publish_once.py`](python/examples/publish_once.py).
|
|
157
|
+
|
|
158
|
+
### Run one subscription graph live or as replay
|
|
159
|
+
|
|
160
|
+
Application code declares only the durable data id:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
prices = fabric.subscribe_data("prices/enriched")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The run owns the policy. `EvaluationMode.REAL_TIME` follows accepted revisions
|
|
167
|
+
from the configured live transport. Simulation deterministically replays the
|
|
168
|
+
executor's start/end interval. Running simulation over one timestamp (or the
|
|
169
|
+
smallest practical interval around it) gives the graph-coordinated equivalent
|
|
170
|
+
of a snapshot without changing application wiring. The complete alternatives
|
|
171
|
+
are in
|
|
172
|
+
[`python/examples/subscription_modes.py`](python/examples/subscription_modes.py).
|
|
173
|
+
|
|
174
|
+
### Load one dataset directly
|
|
175
|
+
|
|
176
|
+
When no graph coordination is required, use the standalone point lookup. It
|
|
177
|
+
loads the latest stored version of one data id by default. Pass `as_of` to
|
|
178
|
+
select the newest revision at or before a cutoff:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
config = fabric.make_memory_fabric_config(prefix="examples/history")
|
|
182
|
+
latest = fabric.load_data(config, "prices/enriched")
|
|
183
|
+
historical = fabric.load_data(config, "prices/enriched", as_of)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The configuration is explicit; the call does not inspect graph state and does
|
|
187
|
+
not solve transitive lineage. It returns `None` when no matching value exists.
|
|
188
|
+
The Python Frame presentation is PyArrow by default and Polars when hgraph's
|
|
189
|
+
Polars compatibility switch is enabled and Polars is installed. See
|
|
190
|
+
[`python/examples/load_data.py`](python/examples/load_data.py) for a runnable
|
|
191
|
+
publish-then-load example using one owning configuration.
|
|
192
|
+
|
|
193
|
+
### Build a derived dataset with automatic lineage
|
|
194
|
+
|
|
195
|
+
Application code may give incoming Frames typed row views, compose ordinary
|
|
196
|
+
hgraph operators, and publish the complete result. Fabric's durable boundary is
|
|
197
|
+
`TS[Frame]`, so the typed result is converted back to that schema-free Frame
|
|
198
|
+
view for publication; its Arrow schema remains part of the stored Frame.
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
raw_prices = fabric.subscribe_data("prices/raw")
|
|
202
|
+
instrument_reference = fabric.subscribe_data("instruments/reference")
|
|
203
|
+
|
|
204
|
+
prices = hg.convert[hg.TS[hg.Frame[Price]]](raw_prices)
|
|
205
|
+
instruments = hg.convert[hg.TS[hg.Frame[Instrument]]](instrument_reference)
|
|
206
|
+
enriched: hg.TS[hg.Frame[EnrichedPrice]] = hg.join(
|
|
207
|
+
prices, instruments, on="symbol", how="left"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
fabric.publish_data(
|
|
211
|
+
"prices/enriched", hg.convert[hg.TS[hg.Frame]](enriched)
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The wiring planner discovers both subscriptions upstream of the joined result,
|
|
216
|
+
so every accepted `prices/enriched` revision records both immediate input
|
|
217
|
+
versions. Reusing one subscription in several computations is safe: each
|
|
218
|
+
publisher records the lineage reachable from its own value edge.
|
|
219
|
+
|
|
220
|
+
[`python/examples/derived_dataset.py`](python/examples/derived_dataset.py)
|
|
221
|
+
contains the complete graph, plus an explicit-lineage variant using
|
|
222
|
+
`dependency_handle()` and `DependencySelection.explicit()`. Prefer automatic
|
|
223
|
+
lineage; use explicit handles only when the semantic dependency is deliberately
|
|
224
|
+
not reachable through the published value's graph ancestry.
|
|
225
|
+
|
|
226
|
+
All example files keep service registration in small local host wrappers. A
|
|
227
|
+
production native host installs `FabricConfig` and the Kafka transport instead;
|
|
228
|
+
the reusable Python component graphs are unchanged.
|
|
229
|
+
|
|
230
|
+
## Production configuration
|
|
231
|
+
|
|
232
|
+
`FabricConfig` is run-scoped state. A host constructs the persistence handles
|
|
233
|
+
once, installs the config in the graph's `GlobalState`, and registers the
|
|
234
|
+
service at wiring time. This local-filesystem host is a useful production-like
|
|
235
|
+
deployment and exercises the same protocol as S3:
|
|
236
|
+
|
|
237
|
+
```cpp
|
|
238
|
+
namespace hgf = hgraph::fabric;
|
|
239
|
+
namespace hgps = hgraph::persistence::store;
|
|
240
|
+
namespace hg = hgraph;
|
|
241
|
+
|
|
242
|
+
auto config = hgf::make_memory_fabric_config("production/blue");
|
|
243
|
+
config.notification_request_limit = 4096;
|
|
244
|
+
config.objects = hgps::make_object_store(
|
|
245
|
+
hgps::ObjectStoreConfig{hgps::LocalLocation{"/srv/fabric/metadata"}});
|
|
246
|
+
config.frames = hgps::make_frame_store(hgps::FrameStoreConfig{
|
|
247
|
+
.location = hgps::LocalLocation{"/srv/fabric/frames"},
|
|
248
|
+
.format = hgps::Format::Parquet,
|
|
249
|
+
.compression = hgps::Compression::Zstd,
|
|
250
|
+
});
|
|
251
|
+
const auto path = hg::service::path("blue-fabric");
|
|
252
|
+
hgf::set_fabric_config(wiring.global_state(), path.value, std::move(config));
|
|
253
|
+
hgf::register_service(wiring, path);
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
For S3, replace both `LocalLocation` values with independently prefixed
|
|
257
|
+
`S3Location` values. Credentials use the persistence extension's ambient,
|
|
258
|
+
explicit or assume-role policy. Prefer ambient workload credentials; never put
|
|
259
|
+
credentials into a data id, Frame metadata, revision, Kafka message, or log.
|
|
260
|
+
The fabric prefix must be a valid relative persistence key and should identify
|
|
261
|
+
one environment. Object-store and topic permissions should be scoped to that
|
|
262
|
+
prefix, with encryption enabled in transit and at rest.
|
|
263
|
+
|
|
264
|
+
A distributed host registers the optional Kafka transport instead of the
|
|
265
|
+
configured in-process notifier. The registration validates idempotent
|
|
266
|
+
production, `acks=all`, and non-dropping queue policies. The repository CMake
|
|
267
|
+
build exports `hgraph::fabric_kafka` when both optional extensions are enabled.
|
|
268
|
+
The standalone `hgraph-fabric` wheel deliberately exports only
|
|
269
|
+
`hgraph::fabric`; it therefore remains installable without Kafka. A native
|
|
270
|
+
distribution that wants the adapter builds with
|
|
271
|
+
`HGRAPH_FABRIC_BUILD_KAFKA=ON` and supplies the installed `hgraph-kafka` SDK.
|
|
272
|
+
|
|
273
|
+
Configuration errors fail at graph startup. Missing stores or notifier,
|
|
274
|
+
invalid prefixes, unavailable Parquet support, unreachable S3, unsafe Kafka
|
|
275
|
+
profiles, and conflicting service registration never fall back to memory.
|
|
276
|
+
|
|
277
|
+
## Operations
|
|
278
|
+
|
|
279
|
+
The `diagnostics()` service publishes a bundle with `metrics` and `events`.
|
|
280
|
+
Metrics remain string values under stable names so lifecycle values and
|
|
281
|
+
counters share one map. Important groups are:
|
|
282
|
+
|
|
283
|
+
* `resolution.*`: calls, forest outcomes, cache hits/misses, examined revisions
|
|
284
|
+
and edges, candidate selections, backtracking depth, and notice-to-ready
|
|
285
|
+
samples/microseconds;
|
|
286
|
+
* `publication.*`: current queue occupancy and its per-data-id bound;
|
|
287
|
+
* `live.*`: conflated notice occupancy and its per-session bound;
|
|
288
|
+
* `transport.notification.*`: pending, delivered, retried, failed, and stale
|
|
289
|
+
correlated delivery reports.
|
|
290
|
+
|
|
291
|
+
Events are keyed by `<component>.<category>` and retain typed `component`,
|
|
292
|
+
`category`, `message`, `retriable`, `fatal`, and `occurrences` fields. Repeated
|
|
293
|
+
events conflate at that path without losing their count. Kafka lifecycle and
|
|
294
|
+
delivery events use their native component/category and severity; synchronous
|
|
295
|
+
store reads and publication boundaries report `store.*` failures before the
|
|
296
|
+
original graph error is rethrown.
|
|
297
|
+
|
|
298
|
+
The root service logs one `info` record at successful start and one at stop,
|
|
299
|
+
including the canonical service path so multiple Fabric services can be
|
|
300
|
+
distinguished without enabling per-tick logging.
|
|
301
|
+
|
|
302
|
+
Alert on corrupt/ambiguous/cyclic forest counts, a sustained non-zero pending
|
|
303
|
+
forest or publication queue, notice-to-ready latency, notification retries or
|
|
304
|
+
failures, and Kafka reconnect/rebalance events. Broker notices are hints:
|
|
305
|
+
durable revision history remains authoritative and reconnect performs a
|
|
306
|
+
durable-head reconciliation.
|
|
307
|
+
|
|
308
|
+
Fabric-owned queues are bounded. Publication accepts at most 1,024 waiting
|
|
309
|
+
requests per data id, each live session retains at most 4,096 conflated
|
|
310
|
+
observed data ids, and the graph transport retains at most 1,024 correlated
|
|
311
|
+
deliveries with at most eight retries. Diagnostic events retain at most 256
|
|
312
|
+
distinct paths; additional paths conflate into `diagnostics.capacity` with an
|
|
313
|
+
occurrence count. Hitting a Fabric work-queue bound is an explicit failure,
|
|
314
|
+
never silent data loss. Kafka real-time ingress deliberately uses RFC 0015's
|
|
315
|
+
standard unbounded burst push-source queue to preserve non-dropping worker
|
|
316
|
+
admission; finite recovery and producer staging retain their configured record
|
|
317
|
+
bounds.
|
|
318
|
+
|
|
319
|
+
V1 retention is intentionally unbounded: one complete Frame per output tick,
|
|
320
|
+
plus one small revision and as-of entry for each accepted input/output tuple.
|
|
321
|
+
A losing concurrent writer may leave an unreferenced candidate Frame. Do not
|
|
322
|
+
apply object-store lifecycle deletion to a live Fabric prefix; retention or
|
|
323
|
+
garbage collection needs a later protocol with ancestry-aware compaction.
|
|
324
|
+
|
|
325
|
+
The first accepted Frame fixes the Arrow schema for a data id. A schema change
|
|
326
|
+
uses a new data id (for example `prices/v2`), runs old and new producers during
|
|
327
|
+
the consumer migration, then retires the old id only under an explicit
|
|
328
|
+
retention plan. Fabric does not reinterpret or transparently migrate stored
|
|
329
|
+
Frames.
|
|
330
|
+
|
|
331
|
+
## Broker conformance
|
|
332
|
+
|
|
333
|
+
The deterministic suite uses librdkafka's mock cluster and the graph-native
|
|
334
|
+
fake service for exact failure injection. Linux CI additionally runs a pinned
|
|
335
|
+
single-node Redpanda broker, stops it while a live graph is running, accepts a
|
|
336
|
+
new durable revision during the outage, observes a retriable delivery failure,
|
|
337
|
+
then restarts the same broker. The test verifies startup image/notice
|
|
338
|
+
de-duplication, reconnect reconciliation, explicit retry, same-key partition
|
|
339
|
+
ordering, and operation with deliberately small non-dropping ingress/outbound
|
|
340
|
+
queues.
|
|
341
|
+
|
|
342
|
+
Run the same scenario locally against Docker with:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
python3 extensions/fabric/tools/run_kafka_broker_conformance.py \
|
|
346
|
+
--test-executable build/extensions/fabric/tests/hgraph_fabric_kafka_tests
|
|
347
|
+
```
|