Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/analytics connection hang #141

Merged
merged 14 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/mlstacks/analytics/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import os
from logging import getLogger
marwan37 marked this conversation as resolved.
Show resolved Hide resolved
from types import TracebackType
from typing import Any, Dict, Optional, Type, cast
from typing import Any, Dict, List, Optional, Type, cast
from uuid import uuid4

import click
Expand All @@ -34,10 +34,24 @@
logger = getLogger(__name__)
marwan37 marked this conversation as resolved.
Show resolved Hide resolved

analytics.write_key = "tU9BJvF05TgC29xgiXuKF7CuYP0zhgnx"
analytics.max_retries = 1

CONFIG_FILENAME = "config.yaml"


def on_error(error: Exception, batch: List[Dict[str, Any]]) -> None:
"""Custom error handler for Segment analytics.

Args:
error: The error that occurred.
batch: Events processed when the error occurred.
"""
logger.debug("Analytics error: %s; Batch: %s", error, batch)


analytics.on_error = on_error


class MLStacksAnalyticsContext:
"""Analytics context manager for MLStacks."""

Expand Down Expand Up @@ -161,7 +175,7 @@ def track_event(
metadata: Dict of metadata to track.

Returns:
True if event is sent successfully, False is not.
True if event is sent successfully, False otherwise.
"""
if metadata is None:
metadata = {}
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/analytics/__init__.py
strickvl marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) ZenML GmbH 2023. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing
# permissions and limitations under the License.
59 changes: 59 additions & 0 deletions tests/unit/analytics/test_custom_on_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) ZenML GmbH 2023. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing
# permissions and limitations under the License.
import logging
marwan37 marked this conversation as resolved.
Show resolved Hide resolved
from typing import Any, Dict, List
from unittest.mock import patch

import pytest
import requests
from segment import analytics

logger = logging.getLogger(__name__)


@pytest.fixture(autouse=True)
def reset_analytics_client():
default_on_error = analytics.on_error

yield

analytics.on_error = default_on_error


def mock_post_failure(*args, **kwargs):
response = requests.Response()
response.status_code = 500
response._content = (
b'{"error": "Simulated failure", "code": "internal_error"}'
)
response.headers["Content-Type"] = "application/json"
return response


def custom_on_error(error: Exception, batch: List[Dict[str, Any]]) -> None:
logger.debug("Analytics error: %s; Batch: %s", error, batch)


@pytest.mark.usefixtures("reset_analytics_client")
def test_segment_custom_on_error_handler_invocation(caplog):
with caplog.at_level(logging.DEBUG):
with patch(
"segment.analytics.request._session.post",
side_effect=mock_post_failure,
):
analytics.track(
"test_user_id", "Test Event", {"property": "value"}
)
analytics.flush()

assert "Analytics error:" in caplog.text
Loading