GeneralManager 0.82.0__tar.gz → 0.82.1__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.
- {generalmanager-0.82.0/src/GeneralManager.egg-info → generalmanager-0.82.1}/PKG-INFO +1 -1
- {generalmanager-0.82.0 → generalmanager-0.82.1}/pyproject.toml +1 -1
- {generalmanager-0.82.0 → generalmanager-0.82.1/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/GeneralManager.egg-info/SOURCES.txt +1 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_index.py +122 -10
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/signals.py +19 -2
- generalmanager-0.82.1/src/general_manager/cache/transaction_barrier.py +283 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/create_many.py +17 -2
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/testing.py +4 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/LICENSE +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/README.md +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/setup.cfg +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_identifiers.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_resolvers.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/apps.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/routing.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/conf.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/base_interface.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/logging.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/general_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/py.typed +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/tests/test_settings.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/tests/test_urls.py +0 -0
- {generalmanager-0.82.0 → generalmanager-0.82.1}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.82.
|
|
3
|
+
Version: 0.82.1
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "GeneralManager"
|
|
7
|
-
version = "0.82.
|
|
7
|
+
version = "0.82.1"
|
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.82.
|
|
3
|
+
Version: 0.82.1
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -82,6 +82,7 @@ src/general_manager/cache/model_dependency_collector.py
|
|
|
82
82
|
src/general_manager/cache/run_context.py
|
|
83
83
|
src/general_manager/cache/run_context_lru.py
|
|
84
84
|
src/general_manager/cache/signals.py
|
|
85
|
+
src/general_manager/cache/transaction_barrier.py
|
|
85
86
|
src/general_manager/chat/__init__.py
|
|
86
87
|
src/general_manager/chat/audit.py
|
|
87
88
|
src/general_manager/chat/bootstrap.py
|
{generalmanager-0.82.0 → generalmanager-0.82.1}/src/general_manager/cache/dependency_index.py
RENAMED
|
@@ -7,7 +7,8 @@ import random
|
|
|
7
7
|
from threading import Event, Thread
|
|
8
8
|
import time
|
|
9
9
|
import uuid
|
|
10
|
-
from collections.abc import Mapping
|
|
10
|
+
from collections.abc import Iterator, Mapping
|
|
11
|
+
from contextlib import contextmanager
|
|
11
12
|
from contextvars import ContextVar
|
|
12
13
|
from datetime import date, datetime
|
|
13
14
|
from time import perf_counter
|
|
@@ -73,6 +74,9 @@ _pending_graphql_rewarm_cache_keys: ContextVar[frozenset[str]] = ContextVar(
|
|
|
73
74
|
"general_manager_pending_graphql_rewarm_cache_keys",
|
|
74
75
|
default=frozenset(),
|
|
75
76
|
)
|
|
77
|
+
_dependency_rewarm_scope_depth: ContextVar[int] = ContextVar(
|
|
78
|
+
"general_manager_dependency_rewarm_scope_depth", default=0
|
|
79
|
+
)
|
|
76
80
|
|
|
77
81
|
|
|
78
82
|
class DependencyLockTimeoutError(TimeoutError):
|
|
@@ -118,6 +122,8 @@ DEPENDENCY_GENERATION_KEY = "dependency_index_generation"
|
|
|
118
122
|
DATA_CHANGE_LOCK_KEY = "dependency_index_data_change_lock"
|
|
119
123
|
DATA_CHANGE_COUNT_KEY = "dependency_index_data_change_count"
|
|
120
124
|
DATA_CHANGE_RECOVERY_KEY = "dependency_index_data_change_recovery"
|
|
125
|
+
DATA_CHANGE_OWNERS_KEY = "dependency_index_data_change_owners"
|
|
126
|
+
COMMITTED_GRAPHQL_REWARM_KEY = "dependency_index_committed_graphql_rewarm"
|
|
121
127
|
LOCK_TIMEOUT = 5 # Lock TTL in seconds
|
|
122
128
|
UNDEFINED = object() # Sentinel for undefined values
|
|
123
129
|
ACTIONS: tuple[Literal["filter"], Literal["exclude"]] = ("filter", "exclude")
|
|
@@ -241,6 +247,15 @@ def _set_dependency_data_change_count(count: int) -> int:
|
|
|
241
247
|
return count
|
|
242
248
|
|
|
243
249
|
|
|
250
|
+
def _get_dependency_data_change_owners() -> frozenset[str]:
|
|
251
|
+
owners = cache.get(DATA_CHANGE_OWNERS_KEY, frozenset())
|
|
252
|
+
if not isinstance(owners, frozenset) or not all(
|
|
253
|
+
isinstance(owner, str) for owner in owners
|
|
254
|
+
):
|
|
255
|
+
raise DependencyBarrierStateError("journal")
|
|
256
|
+
return owners
|
|
257
|
+
|
|
258
|
+
|
|
244
259
|
def _discard_active_context_dependency_cache_state() -> None:
|
|
245
260
|
from general_manager.cache.run_context import current_calculation_run_context
|
|
246
261
|
|
|
@@ -304,10 +319,21 @@ def _clear_data_change_recovery(
|
|
|
304
319
|
|
|
305
320
|
|
|
306
321
|
def _prepare_data_change_recovery(
|
|
307
|
-
token: DependencyLockToken,
|
|
322
|
+
token: DependencyLockToken,
|
|
323
|
+
count: int,
|
|
324
|
+
flag: object,
|
|
325
|
+
owners: frozenset[str],
|
|
326
|
+
generation: int | None = None,
|
|
308
327
|
) -> dict[str, object]:
|
|
309
328
|
_require_data_change_lock_owner(token)
|
|
310
|
-
recovery: dict[str, object] = {
|
|
329
|
+
recovery: dict[str, object] = {
|
|
330
|
+
"owner": token,
|
|
331
|
+
"count": count,
|
|
332
|
+
"flag": flag,
|
|
333
|
+
"owners": owners,
|
|
334
|
+
}
|
|
335
|
+
if generation is not None:
|
|
336
|
+
recovery["generation"] = generation
|
|
311
337
|
cache.set(DATA_CHANGE_RECOVERY_KEY, recovery, None)
|
|
312
338
|
_verify_data_change_cache_value(DATA_CHANGE_RECOVERY_KEY, recovery)
|
|
313
339
|
return recovery
|
|
@@ -321,6 +347,24 @@ def _recover_data_change_barrier(token: DependencyLockToken) -> None:
|
|
|
321
347
|
# previous snapshot never overwrites a later operation's active barrier.
|
|
322
348
|
if not isinstance(recovery, dict) or not isinstance(recovery.get("count"), int):
|
|
323
349
|
raise DependencyBarrierStateError("journal")
|
|
350
|
+
generation = recovery.get("generation")
|
|
351
|
+
if generation is not None:
|
|
352
|
+
if not isinstance(generation, int):
|
|
353
|
+
raise DependencyBarrierStateError("journal")
|
|
354
|
+
_require_data_change_lock_owner(token)
|
|
355
|
+
generation = max(get_dependency_generation(), generation)
|
|
356
|
+
_set_dependency_generation(generation)
|
|
357
|
+
_verify_data_change_cache_value(DEPENDENCY_GENERATION_KEY, generation)
|
|
358
|
+
# Older journals have no owner set. Retain compatibility with #519 recovery.
|
|
359
|
+
if "owners" in recovery:
|
|
360
|
+
owners = recovery["owners"]
|
|
361
|
+
if not isinstance(owners, frozenset) or not all(
|
|
362
|
+
isinstance(owner, str) for owner in owners
|
|
363
|
+
):
|
|
364
|
+
raise DependencyBarrierStateError("journal")
|
|
365
|
+
_require_data_change_lock_owner(token)
|
|
366
|
+
cache.set(DATA_CHANGE_OWNERS_KEY, owners, None)
|
|
367
|
+
_verify_data_change_cache_value(DATA_CHANGE_OWNERS_KEY, owners)
|
|
324
368
|
_require_data_change_lock_owner(token)
|
|
325
369
|
count = recovery["count"]
|
|
326
370
|
_set_dependency_data_change_count(count)
|
|
@@ -359,7 +403,7 @@ def _release_data_change_lock(token: DependencyLockToken) -> None:
|
|
|
359
403
|
logger.exception("dependency data-change mutex release failed")
|
|
360
404
|
|
|
361
405
|
|
|
362
|
-
def begin_dependency_data_change() -> int:
|
|
406
|
+
def begin_dependency_data_change(*, owner: str | None = None) -> int:
|
|
363
407
|
"""Open a publish barrier, preserving a recoverable pre-begin snapshot.
|
|
364
408
|
|
|
365
409
|
Failed starts restore only their own count/flag under the mutex. If cleanup
|
|
@@ -375,8 +419,11 @@ def begin_dependency_data_change() -> int:
|
|
|
375
419
|
_recover_data_change_barrier(lock_token)
|
|
376
420
|
count = _get_dependency_data_change_count()
|
|
377
421
|
flag = cache.get(DATA_CHANGE_LOCK_KEY)
|
|
378
|
-
|
|
379
|
-
|
|
422
|
+
owners = _get_dependency_data_change_owners()
|
|
423
|
+
if owner is not None and owner in owners:
|
|
424
|
+
return get_dependency_generation()
|
|
425
|
+
recovery = {"owner": lock_token, "count": count, "flag": flag, "owners": owners}
|
|
426
|
+
_prepare_data_change_recovery(lock_token, count, flag, owners)
|
|
380
427
|
_require_data_change_lock_owner(lock_token)
|
|
381
428
|
generation = _set_dependency_generation(get_dependency_generation() + 1)
|
|
382
429
|
_verify_data_change_cache_value(DEPENDENCY_GENERATION_KEY, generation)
|
|
@@ -386,6 +433,10 @@ def begin_dependency_data_change() -> int:
|
|
|
386
433
|
_require_data_change_lock_owner(lock_token)
|
|
387
434
|
cache.set(DATA_CHANGE_LOCK_KEY, "1", None)
|
|
388
435
|
_verify_data_change_cache_value(DATA_CHANGE_LOCK_KEY, "1")
|
|
436
|
+
if owner is not None:
|
|
437
|
+
_require_data_change_lock_owner(lock_token)
|
|
438
|
+
cache.set(DATA_CHANGE_OWNERS_KEY, owners | {owner}, None)
|
|
439
|
+
_verify_data_change_cache_value(DATA_CHANGE_OWNERS_KEY, owners | {owner})
|
|
389
440
|
_discard_active_context_dependency_cache_state()
|
|
390
441
|
_clear_data_change_recovery(lock_token, recovery)
|
|
391
442
|
except Exception:
|
|
@@ -400,18 +451,35 @@ def begin_dependency_data_change() -> int:
|
|
|
400
451
|
return generation
|
|
401
452
|
|
|
402
453
|
|
|
403
|
-
def end_dependency_data_change() -> None:
|
|
404
|
-
"""
|
|
454
|
+
def end_dependency_data_change(*, owner: str | None = None) -> None:
|
|
455
|
+
"""Fence in-flight calculations and close one barrier with forward recovery.
|
|
456
|
+
|
|
457
|
+
Owned ends are idempotent, including when cache writes applied then raised.
|
|
458
|
+
A retry completes the journal before checking ownership, so it cannot
|
|
459
|
+
decrement another transaction's barrier.
|
|
460
|
+
"""
|
|
405
461
|
if isinstance(caches["default"], DummyCache):
|
|
406
462
|
return
|
|
407
463
|
lock_token = acquire_lock_with_retry("end_dependency_data_change")
|
|
408
464
|
recovery: dict[str, object] | None = None
|
|
409
465
|
try:
|
|
410
466
|
_recover_data_change_barrier(lock_token)
|
|
467
|
+
owners = _get_dependency_data_change_owners()
|
|
468
|
+
if owner is not None and owner not in owners:
|
|
469
|
+
return
|
|
470
|
+
if owner is not None:
|
|
471
|
+
owners = owners - {owner}
|
|
411
472
|
count = max(_get_dependency_data_change_count() - 1, 0)
|
|
412
473
|
flag = "1" if count else None
|
|
413
|
-
|
|
414
|
-
|
|
474
|
+
generation = get_dependency_generation() + 1
|
|
475
|
+
recovery = {
|
|
476
|
+
"owner": lock_token,
|
|
477
|
+
"count": count,
|
|
478
|
+
"flag": flag,
|
|
479
|
+
"owners": owners,
|
|
480
|
+
"generation": generation,
|
|
481
|
+
}
|
|
482
|
+
_prepare_data_change_recovery(lock_token, count, flag, owners, generation)
|
|
415
483
|
_recover_data_change_barrier(lock_token)
|
|
416
484
|
except Exception:
|
|
417
485
|
if recovery is not None:
|
|
@@ -449,6 +517,50 @@ def drain_invalidated_cache_keys_for_graphql_rewarm() -> tuple[str, ...]:
|
|
|
449
517
|
return cache_keys
|
|
450
518
|
|
|
451
519
|
|
|
520
|
+
def record_committed_graphql_rewarm_keys(cache_keys: Iterable[str]) -> None:
|
|
521
|
+
"""Share committed work with the process that closes the final barrier."""
|
|
522
|
+
keys = frozenset(cache_keys)
|
|
523
|
+
if not keys:
|
|
524
|
+
return
|
|
525
|
+
token = acquire_lock_with_retry("record_committed_graphql_rewarm_keys")
|
|
526
|
+
try:
|
|
527
|
+
existing = cache.get(COMMITTED_GRAPHQL_REWARM_KEY, frozenset())
|
|
528
|
+
cache.set(COMMITTED_GRAPHQL_REWARM_KEY, existing | keys, None)
|
|
529
|
+
finally:
|
|
530
|
+
release_lock(token)
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def drain_committed_graphql_rewarm_keys() -> tuple[str, ...]:
|
|
534
|
+
"""Claim committed keys only when no writer is pausing publication."""
|
|
535
|
+
if not cache.get(COMMITTED_GRAPHQL_REWARM_KEY):
|
|
536
|
+
return ()
|
|
537
|
+
token = acquire_lock_with_retry("drain_committed_graphql_rewarm_keys")
|
|
538
|
+
try:
|
|
539
|
+
if is_dependency_data_change_active():
|
|
540
|
+
return ()
|
|
541
|
+
keys = tuple(sorted(cache.get(COMMITTED_GRAPHQL_REWARM_KEY, frozenset())))
|
|
542
|
+
cache.delete(COMMITTED_GRAPHQL_REWARM_KEY)
|
|
543
|
+
return keys
|
|
544
|
+
finally:
|
|
545
|
+
release_lock(token)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
@contextmanager
|
|
549
|
+
def dependency_rewarm_scope() -> Iterator[None]:
|
|
550
|
+
"""Isolate a mutation's keys from enclosing writes on other connections."""
|
|
551
|
+
depth = _dependency_rewarm_scope_depth.get()
|
|
552
|
+
scope_token = _dependency_rewarm_scope_depth.set(depth + 1)
|
|
553
|
+
token = _pending_graphql_rewarm_cache_keys.set(frozenset()) if depth else None
|
|
554
|
+
try:
|
|
555
|
+
yield
|
|
556
|
+
finally:
|
|
557
|
+
if token is not None:
|
|
558
|
+
remaining = _pending_graphql_rewarm_cache_keys.get()
|
|
559
|
+
_pending_graphql_rewarm_cache_keys.reset(token)
|
|
560
|
+
record_invalidated_cache_keys_for_graphql_rewarm(remaining)
|
|
561
|
+
_dependency_rewarm_scope_depth.reset(scope_token)
|
|
562
|
+
|
|
563
|
+
|
|
452
564
|
def acquire_lock_with_retry(operation: str) -> DependencyLockToken:
|
|
453
565
|
"""
|
|
454
566
|
Acquire the dependency index lock, retrying with exponential backoff.
|
|
@@ -123,6 +123,11 @@ def data_change(
|
|
|
123
123
|
is_dependency_data_change_active,
|
|
124
124
|
)
|
|
125
125
|
from general_manager.cache.run_context import current_calculation_run_context
|
|
126
|
+
from general_manager.cache.transaction_barrier import (
|
|
127
|
+
collect_transaction_rewarm_keys,
|
|
128
|
+
flush_transaction_rewarm_keys,
|
|
129
|
+
hold_dependency_transaction_barrier,
|
|
130
|
+
)
|
|
126
131
|
from general_manager.interface.orm_interface import OrmInterfaceBase
|
|
127
132
|
from general_manager.manager.bulk_create import (
|
|
128
133
|
CreateManyUnsupportedError,
|
|
@@ -179,6 +184,8 @@ def data_change(
|
|
|
179
184
|
transaction_outcome = "rolled_back"
|
|
180
185
|
begin_dependency_data_change()
|
|
181
186
|
try:
|
|
187
|
+
if is_orm_backed:
|
|
188
|
+
hold_dependency_transaction_barrier(database_alias)
|
|
182
189
|
context = current_calculation_run_context()
|
|
183
190
|
if context is not None:
|
|
184
191
|
context.clear_orm_bucket_results()
|
|
@@ -294,6 +301,8 @@ def data_change(
|
|
|
294
301
|
sender=sender,
|
|
295
302
|
**lifecycle_kwargs,
|
|
296
303
|
)
|
|
304
|
+
if is_orm_backed:
|
|
305
|
+
collect_transaction_rewarm_keys(database_alias, completed=True)
|
|
297
306
|
if transaction_scope is not None and transaction_scope.is_outermost:
|
|
298
307
|
transaction_outcome = "committed"
|
|
299
308
|
completed = True
|
|
@@ -333,8 +342,15 @@ def data_change(
|
|
|
333
342
|
raise
|
|
334
343
|
finally:
|
|
335
344
|
try:
|
|
345
|
+
collected = is_orm_backed and collect_transaction_rewarm_keys(
|
|
346
|
+
database_alias, completed=completed
|
|
347
|
+
)
|
|
336
348
|
if not is_dependency_data_change_active():
|
|
337
|
-
|
|
349
|
+
if not collected:
|
|
350
|
+
cache_keys = (
|
|
351
|
+
drain_invalidated_cache_keys_for_graphql_rewarm()
|
|
352
|
+
)
|
|
353
|
+
flush_transaction_rewarm_keys()
|
|
338
354
|
except Exception:
|
|
339
355
|
if primary_exc is not None:
|
|
340
356
|
logger.exception(
|
|
@@ -355,9 +371,10 @@ def data_change(
|
|
|
355
371
|
|
|
356
372
|
@wraps(decorator_source)
|
|
357
373
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
374
|
+
from general_manager.cache.dependency_index import dependency_rewarm_scope
|
|
358
375
|
from general_manager.manager.bulk_create import create_many_signal_scope
|
|
359
376
|
|
|
360
|
-
with create_many_signal_scope():
|
|
377
|
+
with create_many_signal_scope(), dependency_rewarm_scope():
|
|
361
378
|
return perform_change(*args, **kwargs)
|
|
362
379
|
|
|
363
380
|
return wrapper
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""Retain native dependency-cache barriers until database completion."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from functools import wraps
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Callable, cast
|
|
9
|
+
from uuid import uuid4
|
|
10
|
+
|
|
11
|
+
from django.db import connections
|
|
12
|
+
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
13
|
+
from django.utils.connection import ConnectionDoesNotExist
|
|
14
|
+
|
|
15
|
+
from general_manager.logging import get_logger
|
|
16
|
+
|
|
17
|
+
logger = get_logger("cache.transaction_barrier")
|
|
18
|
+
_STATE_ATTRIBUTE = "_general_manager_dependency_barrier"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _clear_transaction_run_cache() -> None:
|
|
22
|
+
from general_manager.cache.run_context import current_calculation_run_context
|
|
23
|
+
|
|
24
|
+
context = current_calculation_run_context()
|
|
25
|
+
if context is not None:
|
|
26
|
+
try:
|
|
27
|
+
context.discard_dependency_cache_state()
|
|
28
|
+
finally:
|
|
29
|
+
# Fallible lease cleanup must not preserve rolled-back DB rows.
|
|
30
|
+
context.clear_orm_bucket_results()
|
|
31
|
+
context.clear_bucket_indexes()
|
|
32
|
+
context.clear_bucket_projections()
|
|
33
|
+
context.clear_trusted_orm_managers()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class _TransactionBarrier:
|
|
38
|
+
connection: BaseDatabaseWrapper
|
|
39
|
+
owner: str | None = None
|
|
40
|
+
release_pending: bool = False
|
|
41
|
+
completion_committed: bool | None = None
|
|
42
|
+
restore_hooks: Callable[[bool], None] | None = None
|
|
43
|
+
|
|
44
|
+
def finish(self, *, committed: bool) -> None:
|
|
45
|
+
from general_manager.cache.dependency_index import end_dependency_data_change
|
|
46
|
+
|
|
47
|
+
if self.owner is None:
|
|
48
|
+
if self.restore_hooks is not None:
|
|
49
|
+
self.restore_hooks(False)
|
|
50
|
+
return
|
|
51
|
+
if self.completion_committed is None:
|
|
52
|
+
self.completion_committed = committed
|
|
53
|
+
self.release_pending = True
|
|
54
|
+
# Keep the owner on an error. Owner-aware end can be retried even when
|
|
55
|
+
# transport failure followed an applied decrement.
|
|
56
|
+
try:
|
|
57
|
+
end_dependency_data_change(owner=self.owner)
|
|
58
|
+
except BaseException:
|
|
59
|
+
try:
|
|
60
|
+
_clear_transaction_run_cache()
|
|
61
|
+
except BaseException:
|
|
62
|
+
logger.exception("Transaction run-cache cleanup failed.")
|
|
63
|
+
raise
|
|
64
|
+
# Ownership reflects the shared barrier, independently of fallible
|
|
65
|
+
# run-local cleanup. A released owner must not block the next write.
|
|
66
|
+
self.owner = None
|
|
67
|
+
self.release_pending = False
|
|
68
|
+
self.completion_committed = None
|
|
69
|
+
try:
|
|
70
|
+
_clear_transaction_run_cache()
|
|
71
|
+
finally:
|
|
72
|
+
if self.restore_hooks is not None:
|
|
73
|
+
self.restore_hooks(False)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _install_completion_hooks(connection: BaseDatabaseWrapper) -> _TransactionBarrier:
|
|
77
|
+
state = _TransactionBarrier(connection)
|
|
78
|
+
original_commit = connection.commit
|
|
79
|
+
original_rollback = connection.rollback
|
|
80
|
+
original_close = connection.close
|
|
81
|
+
original_savepoint_rollback = connection.savepoint_rollback
|
|
82
|
+
original_set_autocommit = connection.set_autocommit
|
|
83
|
+
|
|
84
|
+
@wraps(original_commit)
|
|
85
|
+
def commit() -> None:
|
|
86
|
+
original_commit()
|
|
87
|
+
try:
|
|
88
|
+
state.finish(committed=True)
|
|
89
|
+
except Exception:
|
|
90
|
+
# A DB-backed cache can raise DatabaseError here. SQL already
|
|
91
|
+
# committed; Django must still run its commit callbacks, rather
|
|
92
|
+
# than mistake this ancillary failure for a failed SQL commit.
|
|
93
|
+
logger.exception("Dependency barrier cleanup after commit failed.")
|
|
94
|
+
|
|
95
|
+
@wraps(original_rollback)
|
|
96
|
+
def rollback() -> None:
|
|
97
|
+
original_rollback()
|
|
98
|
+
try:
|
|
99
|
+
state.finish(committed=False)
|
|
100
|
+
except Exception:
|
|
101
|
+
# Atomic may be unwinding a primary mutation/database exception.
|
|
102
|
+
logger.exception("Dependency barrier cleanup after rollback failed.")
|
|
103
|
+
|
|
104
|
+
@wraps(original_close)
|
|
105
|
+
def close() -> None:
|
|
106
|
+
try:
|
|
107
|
+
original_close()
|
|
108
|
+
finally:
|
|
109
|
+
# SQLite's in-memory close is a no-op: it hasn't settled a pending
|
|
110
|
+
# transaction and must not reopen cache publication.
|
|
111
|
+
if connection.connection is None or connection.closed_in_transaction:
|
|
112
|
+
try:
|
|
113
|
+
state.finish(committed=False)
|
|
114
|
+
except Exception:
|
|
115
|
+
logger.exception("Dependency barrier cleanup after close failed.")
|
|
116
|
+
|
|
117
|
+
@wraps(original_savepoint_rollback)
|
|
118
|
+
def savepoint_rollback(sid: str) -> None:
|
|
119
|
+
original_savepoint_rollback(sid)
|
|
120
|
+
if state.owner is not None:
|
|
121
|
+
try:
|
|
122
|
+
_clear_transaction_run_cache()
|
|
123
|
+
except Exception:
|
|
124
|
+
logger.exception(
|
|
125
|
+
"Dependency cache cleanup after savepoint rollback failed."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
@wraps(original_set_autocommit)
|
|
129
|
+
def set_autocommit(
|
|
130
|
+
autocommit: bool, force_begin_transaction_with_broken_autocommit: bool = False
|
|
131
|
+
) -> None:
|
|
132
|
+
# Atomic's finally can restore autocommit while a commit interruption
|
|
133
|
+
# is already unwinding. An ancillary retry must preserve that primary.
|
|
134
|
+
primary: BaseException | None = sys.exception()
|
|
135
|
+
try:
|
|
136
|
+
original_set_autocommit(
|
|
137
|
+
autocommit,
|
|
138
|
+
force_begin_transaction_with_broken_autocommit,
|
|
139
|
+
)
|
|
140
|
+
except BaseException as error:
|
|
141
|
+
primary = error
|
|
142
|
+
raise
|
|
143
|
+
finally:
|
|
144
|
+
# User on_commit callbacks run inside set_autocommit and can raise
|
|
145
|
+
# after the DB already committed. Cleanup must still run.
|
|
146
|
+
if autocommit and connection.autocommit and not connection.in_atomic_block:
|
|
147
|
+
rolled_back = state.completion_committed is False
|
|
148
|
+
try:
|
|
149
|
+
state.finish(committed=True)
|
|
150
|
+
flush_transaction_rewarm_keys()
|
|
151
|
+
except Exception:
|
|
152
|
+
if primary is None and not rolled_back:
|
|
153
|
+
raise
|
|
154
|
+
logger.exception("Dependency barrier cleanup after commit failed.")
|
|
155
|
+
|
|
156
|
+
hooks = (
|
|
157
|
+
("commit", commit),
|
|
158
|
+
("rollback", rollback),
|
|
159
|
+
("close", close),
|
|
160
|
+
("savepoint_rollback", savepoint_rollback),
|
|
161
|
+
("set_autocommit", set_autocommit),
|
|
162
|
+
)
|
|
163
|
+
missing = object()
|
|
164
|
+
previous = {name: vars(connection).get(name, missing) for name, _ in hooks}
|
|
165
|
+
|
|
166
|
+
def restore_hooks(force: bool) -> None:
|
|
167
|
+
# Remove only our instance overrides. Restoring class lookup avoids
|
|
168
|
+
# retaining bound-method cycles on completed thread-local connections.
|
|
169
|
+
# Keep the completion setter until Django restores autocommit. Eager
|
|
170
|
+
# warm-up must not open a new SQL transaction before that restoration.
|
|
171
|
+
defer_dispatch = (
|
|
172
|
+
not force
|
|
173
|
+
and connection.connection is not None
|
|
174
|
+
and not connection.autocommit
|
|
175
|
+
and not connection.closed_in_transaction
|
|
176
|
+
)
|
|
177
|
+
for name, hook in hooks:
|
|
178
|
+
if defer_dispatch and name in {"close", "set_autocommit"}:
|
|
179
|
+
continue
|
|
180
|
+
if vars(connection).get(name) is hook:
|
|
181
|
+
if previous[name] is missing:
|
|
182
|
+
vars(connection).pop(name, None)
|
|
183
|
+
else:
|
|
184
|
+
setattr(connection, name, previous[name])
|
|
185
|
+
if not defer_dispatch:
|
|
186
|
+
if getattr(connection, _STATE_ATTRIBUTE, None) is state:
|
|
187
|
+
vars(connection).pop(_STATE_ATTRIBUTE, None)
|
|
188
|
+
state.restore_hooks = None
|
|
189
|
+
|
|
190
|
+
state.restore_hooks = restore_hooks
|
|
191
|
+
for name, hook in hooks:
|
|
192
|
+
setattr(connection, name, hook)
|
|
193
|
+
setattr(connection, _STATE_ATTRIBUTE, state)
|
|
194
|
+
return state
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def hold_dependency_transaction_barrier(database_alias: str) -> None:
|
|
198
|
+
"""Hold one owned barrier through all savepoints on a writing connection."""
|
|
199
|
+
from general_manager.cache.dependency_index import begin_dependency_data_change
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
connection = connections[database_alias]
|
|
203
|
+
except ConnectionDoesNotExist:
|
|
204
|
+
# Lightweight signal callers sometimes replace transaction.atomic.
|
|
205
|
+
# The real atomic operation remains responsible for rejecting aliases.
|
|
206
|
+
return
|
|
207
|
+
if not connection.in_atomic_block and (
|
|
208
|
+
connection.autocommit
|
|
209
|
+
or (connection.connection is None and connection.settings_dict["AUTOCOMMIT"])
|
|
210
|
+
):
|
|
211
|
+
return
|
|
212
|
+
state = cast(
|
|
213
|
+
_TransactionBarrier | None, getattr(connection, _STATE_ATTRIBUTE, None)
|
|
214
|
+
)
|
|
215
|
+
if state is not None:
|
|
216
|
+
if state.release_pending:
|
|
217
|
+
state.finish(committed=False)
|
|
218
|
+
if state.owner is None:
|
|
219
|
+
# A manual transaction can write again before restoring
|
|
220
|
+
# autocommit. Replace its completed lifecycle before acquiring
|
|
221
|
+
# another owner, including the deferred completion setter.
|
|
222
|
+
if state.restore_hooks is not None:
|
|
223
|
+
state.restore_hooks(True)
|
|
224
|
+
state = None
|
|
225
|
+
if state is None:
|
|
226
|
+
state = _install_completion_hooks(connection)
|
|
227
|
+
if state.owner is None:
|
|
228
|
+
owner = uuid4().hex
|
|
229
|
+
try:
|
|
230
|
+
begin_dependency_data_change(owner=owner)
|
|
231
|
+
except BaseException:
|
|
232
|
+
if state.restore_hooks is not None:
|
|
233
|
+
state.restore_hooks(True)
|
|
234
|
+
raise
|
|
235
|
+
state.owner = owner
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def collect_transaction_rewarm_keys(database_alias: str, *, completed: bool) -> bool:
|
|
239
|
+
"""Register eligible work with Django's savepoint-aware commit callbacks.
|
|
240
|
+
|
|
241
|
+
Callbacks own only optional warm-up work, never the transaction barrier.
|
|
242
|
+
Discarding them on rollback therefore cannot leak a barrier.
|
|
243
|
+
"""
|
|
244
|
+
from general_manager.cache.dependency_index import (
|
|
245
|
+
drain_invalidated_cache_keys_for_graphql_rewarm,
|
|
246
|
+
record_committed_graphql_rewarm_keys,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
connection = connections[database_alias]
|
|
251
|
+
except ConnectionDoesNotExist:
|
|
252
|
+
return False
|
|
253
|
+
if connection.connection is None or (
|
|
254
|
+
not connection.in_atomic_block and not connection.autocommit
|
|
255
|
+
):
|
|
256
|
+
return False
|
|
257
|
+
keys = drain_invalidated_cache_keys_for_graphql_rewarm()
|
|
258
|
+
if completed and keys:
|
|
259
|
+
|
|
260
|
+
def committed_rewarm() -> None:
|
|
261
|
+
try:
|
|
262
|
+
record_committed_graphql_rewarm_keys(keys)
|
|
263
|
+
flush_transaction_rewarm_keys()
|
|
264
|
+
except Exception:
|
|
265
|
+
logger.exception("GraphQL warm-up requeue failed.")
|
|
266
|
+
|
|
267
|
+
connection.on_commit(committed_rewarm)
|
|
268
|
+
return True
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def flush_transaction_rewarm_keys() -> None:
|
|
272
|
+
"""Dispatch shared committed work after the final mutation barrier closes."""
|
|
273
|
+
try:
|
|
274
|
+
from general_manager.cache.dependency_index import (
|
|
275
|
+
drain_committed_graphql_rewarm_keys,
|
|
276
|
+
)
|
|
277
|
+
from general_manager.api.graphql_warmup import enqueue_graphql_recipe_warmup
|
|
278
|
+
|
|
279
|
+
keys = drain_committed_graphql_rewarm_keys()
|
|
280
|
+
if keys:
|
|
281
|
+
enqueue_graphql_recipe_warmup(keys)
|
|
282
|
+
except Exception:
|
|
283
|
+
logger.exception("GraphQL warm-up requeue failed.")
|
|
@@ -286,6 +286,7 @@ class OrmCreateManyCapability(BaseCapability):
|
|
|
286
286
|
if use_bulk_sql:
|
|
287
287
|
from general_manager.cache.dependency_index import (
|
|
288
288
|
begin_dependency_data_change,
|
|
289
|
+
dependency_rewarm_scope,
|
|
289
290
|
drain_invalidated_cache_keys_for_graphql_rewarm,
|
|
290
291
|
end_dependency_data_change,
|
|
291
292
|
is_dependency_data_change_active,
|
|
@@ -293,6 +294,10 @@ class OrmCreateManyCapability(BaseCapability):
|
|
|
293
294
|
from general_manager.cache.run_context import (
|
|
294
295
|
current_calculation_run_context,
|
|
295
296
|
)
|
|
297
|
+
from general_manager.cache.transaction_barrier import (
|
|
298
|
+
collect_transaction_rewarm_keys,
|
|
299
|
+
hold_dependency_transaction_barrier,
|
|
300
|
+
)
|
|
296
301
|
from general_manager.cache.batch_refresh import (
|
|
297
302
|
flush_batch_refresh_callbacks,
|
|
298
303
|
)
|
|
@@ -302,9 +307,15 @@ class OrmCreateManyCapability(BaseCapability):
|
|
|
302
307
|
|
|
303
308
|
run_context = current_calculation_run_context()
|
|
304
309
|
bulk_succeeded = False
|
|
305
|
-
with
|
|
310
|
+
with (
|
|
311
|
+
create_many_signal_scope(),
|
|
312
|
+
dependency_rewarm_scope(),
|
|
313
|
+
):
|
|
306
314
|
begin_dependency_data_change()
|
|
307
315
|
try:
|
|
316
|
+
hold_dependency_transaction_barrier(
|
|
317
|
+
database_alias
|
|
318
|
+
)
|
|
308
319
|
if run_context is not None:
|
|
309
320
|
run_context.clear_orm_bucket_results()
|
|
310
321
|
run_context.clear_bucket_indexes()
|
|
@@ -347,9 +358,13 @@ class OrmCreateManyCapability(BaseCapability):
|
|
|
347
358
|
run_context.clear_bucket_projections()
|
|
348
359
|
run_context.clear_trusted_orm_managers()
|
|
349
360
|
end_dependency_data_change()
|
|
361
|
+
collected = collect_transaction_rewarm_keys(
|
|
362
|
+
database_alias, completed=bulk_succeeded
|
|
363
|
+
)
|
|
350
364
|
cache_keys = (
|
|
351
365
|
drain_invalidated_cache_keys_for_graphql_rewarm()
|
|
352
|
-
if not
|
|
366
|
+
if not collected
|
|
367
|
+
and not is_dependency_data_change_active()
|
|
353
368
|
else ()
|
|
354
369
|
)
|
|
355
370
|
if bulk_succeeded and cache_keys:
|
|
@@ -25,6 +25,8 @@ from general_manager.cache.cache_decorator import _SENTINEL
|
|
|
25
25
|
from general_manager.cache.dependency_index import (
|
|
26
26
|
DATA_CHANGE_COUNT_KEY,
|
|
27
27
|
DATA_CHANGE_LOCK_KEY,
|
|
28
|
+
DATA_CHANGE_OWNERS_KEY,
|
|
29
|
+
COMMITTED_GRAPHQL_REWARM_KEY,
|
|
28
30
|
DATA_CHANGE_RECOVERY_KEY,
|
|
29
31
|
DEPENDENCY_GENERATION_KEY,
|
|
30
32
|
INDEX_KEY,
|
|
@@ -50,6 +52,8 @@ _original_get_app: Callable[[str], AppConfig | None] = (
|
|
|
50
52
|
_DEPENDENCY_COORDINATION_KEYS = {
|
|
51
53
|
DATA_CHANGE_COUNT_KEY,
|
|
52
54
|
DATA_CHANGE_LOCK_KEY,
|
|
55
|
+
DATA_CHANGE_OWNERS_KEY,
|
|
56
|
+
COMMITTED_GRAPHQL_REWARM_KEY,
|
|
53
57
|
DATA_CHANGE_RECOVERY_KEY,
|
|
54
58
|
DEPENDENCY_GENERATION_KEY,
|
|
55
59
|
INDEX_KEY,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{generalmanager-0.82.0 → generalmanager-0.82.1}/src/GeneralManager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|