-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(performance improvement - litellm sdk + proxy) - ensure litellm does…
… not create unnecessary threads when running async functions (#7680) * fix handle_sync_success_callbacks_for_async_calls * fix handle_sync_success_callbacks_for_async_calls * fix linting / testing errors * use handle_sync_success_callbacks_for_async_calls * add unit testing for logging fixes
- Loading branch information
1 parent
a3e65c9
commit 5c870c0
Showing
4 changed files
with
264 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
tests/logging_callback_tests/test_unit_test_litellm_logging.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import json | ||
import os | ||
import sys | ||
from datetime import datetime | ||
from unittest.mock import AsyncMock | ||
|
||
sys.path.insert( | ||
0, os.path.abspath("../..") | ||
) # Adds the parent directory to the system-path | ||
|
||
from typing import Literal | ||
|
||
import pytest | ||
import litellm | ||
from litellm.litellm_core_utils.litellm_logging import Logging | ||
from litellm.proxy.hooks.max_budget_limiter import _PROXY_MaxBudgetLimiter | ||
from litellm.proxy.hooks.cache_control_check import _PROXY_CacheControlCheck | ||
from litellm._service_logger import ServiceLogging | ||
import asyncio | ||
|
||
|
||
from litellm.litellm_core_utils.litellm_logging import Logging | ||
import litellm | ||
|
||
service_logger = ServiceLogging() | ||
|
||
|
||
def setup_logging(): | ||
return Logging( | ||
model="gpt-4o", | ||
messages=[{"role": "user", "content": "Hello, world!"}], | ||
stream=False, | ||
call_type="completion", | ||
start_time=datetime.now(), | ||
litellm_call_id="123", | ||
function_id="456", | ||
) | ||
|
||
|
||
def test_get_callback_name(): | ||
""" | ||
Ensure we can get the name of a callback | ||
""" | ||
logging = setup_logging() | ||
|
||
# Test function with __name__ | ||
def test_func(): | ||
pass | ||
|
||
assert logging._get_callback_name(test_func) == "test_func" | ||
|
||
# Test function with __func__ | ||
class TestClass: | ||
def method(self): | ||
pass | ||
|
||
bound_method = TestClass().method | ||
assert logging._get_callback_name(bound_method) == "method" | ||
|
||
# Test string callback | ||
assert logging._get_callback_name("callback_string") == "callback_string" | ||
|
||
|
||
def test_is_internal_litellm_proxy_callback(): | ||
""" | ||
Ensure we can determine if a callback is an internal litellm proxy callback | ||
eg. `_PROXY_MaxBudgetLimiter`, `_PROXY_CacheControlCheck` | ||
""" | ||
logging = setup_logging() | ||
|
||
assert logging._is_internal_litellm_proxy_callback(_PROXY_MaxBudgetLimiter) == True | ||
|
||
# Test non-internal callbacks | ||
def regular_callback(): | ||
pass | ||
|
||
assert logging._is_internal_litellm_proxy_callback(regular_callback) == False | ||
|
||
# Test string callback | ||
assert logging._is_internal_litellm_proxy_callback("callback_string") == False | ||
|
||
|
||
def test_should_run_sync_callbacks_for_async_calls(): | ||
""" | ||
Ensure we can determine if we should run sync callbacks for async calls | ||
Note: We don't want to run sync callbacks for async calls because we don't want to block the event loop | ||
""" | ||
logging = setup_logging() | ||
|
||
# Test with no callbacks | ||
logging.dynamic_success_callbacks = None | ||
litellm.success_callback = [] | ||
assert logging._should_run_sync_callbacks_for_async_calls() == False | ||
|
||
# Test with regular callback | ||
def regular_callback(): | ||
pass | ||
|
||
litellm.success_callback = [regular_callback] | ||
assert logging._should_run_sync_callbacks_for_async_calls() == True | ||
|
||
# Test with internal callback only | ||
litellm.success_callback = [_PROXY_MaxBudgetLimiter] | ||
assert logging._should_run_sync_callbacks_for_async_calls() == False | ||
|
||
|
||
def test_remove_internal_litellm_callbacks(): | ||
logging = setup_logging() | ||
|
||
def regular_callback(): | ||
pass | ||
|
||
callbacks = [ | ||
regular_callback, | ||
_PROXY_MaxBudgetLimiter, | ||
_PROXY_CacheControlCheck, | ||
"string_callback", | ||
] | ||
|
||
filtered = logging._remove_internal_litellm_callbacks(callbacks) | ||
assert len(filtered) == 2 # Should only keep regular_callback and string_callback | ||
assert regular_callback in filtered | ||
assert "string_callback" in filtered | ||
assert _PROXY_MaxBudgetLimiter not in filtered | ||
assert _PROXY_CacheControlCheck not in filtered |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters