diff --git a/api/core/workflows_services.py b/api/core/workflows_services.py index 2547681e56a2..3b706e3e3c87 100644 --- a/api/core/workflows_services.py +++ b/api/core/workflows_services.py @@ -4,10 +4,8 @@ from django.db import transaction from django.utils import timezone -from environments.tasks import rebuild_environment_document from features.versioning.models import EnvironmentFeatureVersion from features.versioning.signals import environment_feature_version_published -from features.versioning.tasks import trigger_update_version_webhooks from features.workflows.core.exceptions import ChangeRequestNotApprovedError if TYPE_CHECKING: @@ -86,18 +84,6 @@ def _publish_environment_feature_versions( ) for environment_feature_version in environment_feature_versions: - trigger_update_version_webhooks.delay( - kwargs={ - "environment_feature_version_uuid": str( - environment_feature_version.uuid - ) - }, - delay_until=environment_feature_version.live_from, - ) - rebuild_environment_document.delay( - kwargs={"environment_id": self.change_request.environment_id}, - delay_until=environment_feature_version.live_from, - ) environment_feature_version_published.send( EnvironmentFeatureVersion, instance=environment_feature_version ) diff --git a/api/features/versioning/receivers.py b/api/features/versioning/receivers.py index 175fd1113f55..e6de2b24a249 100644 --- a/api/features/versioning/receivers.py +++ b/api/features/versioning/receivers.py @@ -44,7 +44,10 @@ def cache_fields(instance: EnvironmentFeatureVersion, **kwargs): # type: ignore @receiver(environment_feature_version_published, sender=EnvironmentFeatureVersion) -def update_environment_document(instance: EnvironmentFeatureVersion, **kwargs): # type: ignore[no-untyped-def] +def update_environment_document(instance: EnvironmentFeatureVersion, **kwargs) -> None: # type: ignore[no-untyped-def] + now = timezone.now() + if not instance.live_from or instance.live_from <= now: + return rebuild_environment_document.delay( kwargs={"environment_id": instance.environment_id}, delay_until=instance.live_from, diff --git a/api/tests/unit/features/versioning/test_unit_versioning_receiver.py b/api/tests/unit/features/versioning/test_unit_versioning_receiver.py new file mode 100644 index 000000000000..ff499cc04c2b --- /dev/null +++ b/api/tests/unit/features/versioning/test_unit_versioning_receiver.py @@ -0,0 +1,46 @@ +from datetime import timedelta +from unittest import mock + +from django.utils import timezone + +from features.versioning.receivers import update_environment_document + + +def test_update_environment_document__immediate_publish__does_not_schedule_rebuild() -> ( + None +): + # Given + mock_instance = mock.MagicMock() + mock_instance.live_from = timezone.now() - timedelta(seconds=1) + mock_instance.environment_id = 1 + + # When + with mock.patch( + "features.versioning.receivers.rebuild_environment_document" + ) as mock_rebuild: + update_environment_document(instance=mock_instance) + + # Then + mock_rebuild.delay.assert_not_called() + + +def test_update_environment_document__scheduled_publish__schedules_rebuild_at_live_from() -> ( + None +): + # Given + future = timezone.now() + timedelta(hours=1) + mock_instance = mock.MagicMock() + mock_instance.live_from = future + mock_instance.environment_id = 1 + + # When + with mock.patch( + "features.versioning.receivers.rebuild_environment_document" + ) as mock_rebuild: + update_environment_document(instance=mock_instance) + + # Then + mock_rebuild.delay.assert_called_once_with( + kwargs={"environment_id": 1}, + delay_until=future, + ) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index 4068d34021d4..1be447aeb132 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -699,11 +699,8 @@ def test_change_request_commit__v2_versioning__publishes_environment_feature_ver change_request.environment_feature_versions.add(environment_feature_version) - mock_rebuild_environment_document_task = mocker.patch( - "core.workflows_services.rebuild_environment_document" - ) - mock_trigger_update_version_webhooks = mocker.patch( - "core.workflows_services.trigger_update_version_webhooks" + mock_signal = mocker.patch( + "core.workflows_services.environment_feature_version_published" ) # When @@ -715,15 +712,8 @@ def test_change_request_commit__v2_versioning__publishes_environment_feature_ver assert environment_feature_version.published_by == admin_user assert environment_feature_version.live_from == now - mock_rebuild_environment_document_task.delay.assert_called_once_with( - kwargs={"environment_id": environment.id}, - delay_until=environment_feature_version.live_from, - ) - mock_trigger_update_version_webhooks.delay.assert_called_once_with( - kwargs={ - "environment_feature_version_uuid": str(environment_feature_version.uuid) - }, - delay_until=environment_feature_version.live_from, + mock_signal.send.assert_called_once_with( + EnvironmentFeatureVersion, instance=environment_feature_version ) diff --git a/docs/docs/deployment-self-hosting/observability/_events-catalogue.md b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md index 1d126c0430d7..e69de29bb2d1 100644 --- a/docs/docs/deployment-self-hosting/observability/_events-catalogue.md +++ b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md @@ -1,407 +0,0 @@ - -### `api_usage.notification.evaluated` - -Logged at `info` from: - - `api/organisations/task_helpers.py:153` - -Attributes: - - `allowed_api_calls` - - `api_usage` - - `api_usage_percent` - - `matched_threshold` - - `organisation.id` - - `period_ends_at` - - `period_starts_at` - -### `api_usage.notification.missing_billing_starts_at` - -Logged at `error` from: - - `api/organisations/task_helpers.py:118` - -Attributes: - - `organisation.id` - -### `api_usage.notification.sent` - -Logged at `info` from: - - `api/organisations/task_helpers.py:176` - -Attributes: - - `matched_threshold` - - `organisation.id` - -### `app_analytics.no_analytics_database_configured` - -Logged at `warning` from: - - `api/app_analytics/analytics_db_service.py:74` - - `api/app_analytics/analytics_db_service.py:210` - -Attributes: - - `details` - -### `billing.seat.added` - -Logged at `info` from: - - `api/organisations/chargebee/chargebee.py:239` - -Attributes: - - `addon.id` - - `organisation.id` - - `seats.new` - - `seats.previous` - - `subscription.id` - -### `code_references.cleanup_issues.created` - -Logged at `info` from: - - `api/integrations/github/views.py:388` - -Attributes: - - `issues_created.count` - - `organisation.id` - -### `code_references.scan.created` - -Logged at `info` from: - - `api/projects/code_references/views.py:41` - -Attributes: - - `code_references.count` - - `feature.count` - - `organisation.id` - -### `dynamodb.environment_document_compressed` - -Logged at `info` from: - - `api/environments/dynamodb/wrappers/environment_wrapper.py:92` - -Attributes: - - `environment_api_key` - - `environment_id` - -### `feature_health.feature_health_event_dismissal_not_supported` - -Logged at `warning` from: - - `api/features/feature_health/services.py:127` - -Attributes: - - `feature_health_event_external_id` - - `feature_health_event_id` - - `feature_health_event_type` - - `provider_name` - -### `feature_health.feature_health_provider_error` - -Logged at `error` from: - - `api/features/feature_health/services.py:50` - -Attributes: - - `exc_info` - - `provider_id` - - `provider_name` - -### `feature_health.invalid_feature_health_webhook_path_requested` - -Logged at `warning` from: - - `api/features/feature_health/providers/services.py:30` - -Attributes: - - `path` - -### `gitlab.api_call.failed` - -Logged at `error` from: - - `api/integrations/gitlab/views/browse_gitlab.py:59` - -Attributes: - - `exc_info` - - `organisation.id` - - `project.id` - -### `gitlab.comment.post_failed` - -Logged at `warning` from: - - `api/integrations/gitlab/services/comments.py:69` - -Attributes: - - `exc_info` - - `feature.id` - - `gitlab.project.path` - - `gitlab.resource.iid` - - `organisation.id` - - `project.id` - -### `gitlab.comment.posted` - -Logged at `info` from: - - `api/integrations/gitlab/services/comments.py:71` - -Attributes: - - `feature.id` - - `gitlab.project.path` - - `gitlab.resource.iid` - - `organisation.id` - - `project.id` - -### `gitlab.configuration.created` - -Logged at `info` from: - - `api/integrations/gitlab/views/configuration.py:26` - -Attributes: - - `gitlab_instance_url` - - `organisation.id` - - `project.id` - -### `gitlab.configuration.updated` - -Logged at `info` from: - - `api/integrations/gitlab/views/configuration.py:34` - -Attributes: - - `gitlab_instance_url` - - `organisation.id` - - `project.id` - -### `gitlab.feature.tagged` - -Logged at `info` from: - - `api/integrations/gitlab/services/tagging.py:89` - -Attributes: - - `action` - - `feature.id` - - `object_kind` - - `organisation.id` - - `project.id` - - `tag.label` - -### `gitlab.label.created` - -Logged at `info` from: - - `api/integrations/gitlab/services/labels.py:66` - -Attributes: - - `feature.id` - - `gitlab_project.path` - - `organisation.id` - - `project.id` - - `resource.iid` - - `resource.type` - -### `gitlab.label.failed` - -Logged at `exception` from: - - `api/integrations/gitlab/services/labels.py:76` - -Attributes: - - `feature.id` - - `gitlab_project.path` - - `organisation.id` - - `project.id` - - `resource.iid` - - `resource.type` - -### `gitlab.label.removal_failed` - -Logged at `exception` from: - - `api/integrations/gitlab/tasks.py:189` - -Attributes: - - `feature.id` - - `gitlab_project.path` - - `project.id` - - `resource.iid` - - `resource.type` - -### `gitlab.label.removed` - -Logged at `info` from: - - `api/integrations/gitlab/tasks.py:187` - -Attributes: - - `feature.id` - - `gitlab_project.path` - - `project.id` - - `resource.iid` - - `resource.type` - -### `gitlab.resource.linked` - -Logged at `info` from: - - `api/integrations/vcs/services.py:35` - -Attributes: - - `feature.id` - - `organisation.id` - - `project.id` - - `resource.type` - -### `gitlab.resource.unlinked` - -Logged at `info` from: - - `api/integrations/vcs/services.py:70` - -Attributes: - - `feature.id` - - `organisation.id` - - `project.id` - - `resource.type` - -### `gitlab.webhook.deregistered` - -Logged at `info` from: - - `api/integrations/gitlab/services/webhooks.py:157` - -Attributes: - - `gitlab.hook.id` - - `gitlab.project.id` - - `organisation.id` - - `project.id` - -### `gitlab.webhook.deregistration_failed` - -Logged at `warning` from: - - `api/integrations/gitlab/services/webhooks.py:150` - -Attributes: - - `exc_info` - - `gitlab.hook.id` - - `gitlab.project.id` - - `organisation.id` - - `project.id` - -### `gitlab.webhook.registered` - -Logged at `info` from: - - `api/integrations/gitlab/services/webhooks.py:110` - -Attributes: - - `gitlab.hook.id` - - `gitlab.project.id` - - `gitlab.project.path` - - `organisation.id` - - `project.id` - -### `gitlab.webhook.registration_failed` - -Logged at `error` from: - - `api/integrations/gitlab/services/webhooks.py:95` - -Attributes: - - `exc_info` - - `gitlab.project.path` - - `organisation.id` - - `project.id` - -### `launch_darkly.import_failed` - -Logged at `exception` from: - - `api/integrations/launch_darkly/tasks.py:36` - -Attributes: - - `import_request_id` - - `ld_project_key` - - `organisation_id` - - `project_id` - -### `launch_darkly.import_rate_limit_reached` - -Logged at `warning` from: - - `api/integrations/launch_darkly/tasks.py:26` - -Attributes: - - `error_message` - - `import_request_id` - - `ld_project_key` - - `organisation_id` - - `project_id` - - `retry_at` - -### `platform_hub.no_analytics_database_configured` - -Logged at `warning` from: - - `api/platform_hub/services.py:116` - - `api/platform_hub/services.py:206` - - `api/platform_hub/services.py:428` - -Attributes: - -### `segments.serializers.segment_revision_created` - -Logged at `info` from: - - `api/segments/serializers.py:142` - -Attributes: - - `revision_id` - - `segment_id` - -### `sentry_change_tracking.integration_error` - -Logged at `warning` from: - - `api/integrations/sentry/change_tracking.py:109` - -Attributes: - - `feature_name` - - `sentry_action` - - `sentry_response_body` - - `sentry_response_status` - -### `sentry_change_tracking.request_failure` - -Logged at `warning` from: - - `api/integrations/sentry/change_tracking.py:99` - -Attributes: - - `error` - - `feature_name` - - `sentry_action` - -### `sentry_change_tracking.sending` - -Logged at `debug` from: - - `api/integrations/sentry/change_tracking.py:84` - -Attributes: - - `feature_name` - - `headers` - - `payload` - - `sentry_action` - - `url` - -### `sentry_change_tracking.success` - -Logged at `info` from: - - `api/integrations/sentry/change_tracking.py:106` - -Attributes: - - `feature_name` - - `sentry_action` - -### `workflows.change_request.committed` - -Logged at `info` from: - - `api/core/workflows_services.py:39` - -Attributes: - - `environment.id` - - `feature_states.count` - - `organisation.id` - -### `workflows.missing_live_segment` - -Logged at `warning` from: - - `api/core/workflows_services.py:114` - -Attributes: - - `draft_segment` - -### `workflows.segment_revision_created` - -Logged at `info` from: - - `api/core/workflows_services.py:119` - -Attributes: - - `revision_id` - - `segment_id` -