Skip to content

Commit 50b1308

Browse files
committed
python(feat): Reduce API calls when creating rules with caching.
This is optional and only enabled by default for rule evaluation.
1 parent a1d2504 commit 50b1308

3 files changed

Lines changed: 51 additions & 12 deletions

File tree

python/lib/sift_py/asset/_internal/shared.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Optional, cast
1+
from typing import List, Optional, Tuple, Union, cast
22

33
from sift.assets.v1.assets_pb2 import Asset, ListAssetsRequest, ListAssetsResponse
44
from sift.assets.v1.assets_pb2_grpc import AssetServiceStub
@@ -7,16 +7,16 @@
77

88
def list_assets_impl(
99
_asset_service_stub: AssetServiceStub,
10-
names: Optional[List[str]] = None,
11-
ids: Optional[List[str]] = None,
10+
names: Optional[Union[Tuple[str], List[str]]] = None,
11+
ids: Optional[Union[Tuple[str], List[str]]] = None,
1212
) -> List[Asset]:
1313
"""
1414
Lists assets in an organization.
1515
1616
Args:
1717
_asset_service_stub: The asset service stub to use.
18-
names: Optional list of names to filter by.
19-
ids: Optional list of IDs to filter by.
18+
names: Optional collection of names to filter by.
19+
ids: Optional collection of IDs to filter by.
2020
2121
Returns:
2222
A list of assets matching the criteria.

python/lib/sift_py/rule/service.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4+
from functools import cache
45
from pathlib import Path
5-
from typing import Any, Dict, List, Optional, Union, cast
6+
from typing import Any, Dict, List, Optional, Tuple, Union, cast
67

78
from sift.annotations.v1.annotations_pb2 import AnnotationType
89
from sift.assets.v1.assets_pb2 import Asset
910
from sift.assets.v1.assets_pb2_grpc import AssetServiceStub
11+
from sift.channels.v3.channels_pb2 import Channel as ChannelPb
1012
from sift.channels.v3.channels_pb2_grpc import ChannelServiceStub
13+
from sift.common.type.v1.user_pb2 import User as UserPb
1114
from sift.rules.v1.rules_pb2 import (
1215
ANNOTATION,
1316
AnnotationActionConfiguration,
@@ -53,18 +56,25 @@
5356
class RuleService:
5457
"""
5558
A service for managing rules. Allows for loading rules from YAML and creating or updating them in the Sift API.
59+
60+
Args:
61+
channel: The configured Sift channel.
62+
enable_caching: Enable caching on various API calls to speed up rule creation. Use this for short lived
63+
instantiations of the RuleService where assets, channels, users are unlikely to change.
5664
"""
5765

5866
_asset_service_stub: AssetServiceStub
5967
_channel_service_stub: ChannelServiceStub
6068
_rule_service_stub: RuleServiceStub
6169
_user_service_stub: UserServiceStub
70+
_enable_caching: bool
6271

63-
def __init__(self, channel: SiftChannel):
72+
def __init__(self, channel: SiftChannel, enable_caching=False):
6473
self._asset_service_stub = AssetServiceStub(channel)
6574
self._channel_service_stub = ChannelServiceStub(channel)
6675
self._rule_service_stub = RuleServiceStub(channel)
6776
self._user_service_stub = UserServiceStub(channel)
77+
self._enable_caching = enable_caching
6878

6979
def load_rules_from_yaml(
7080
self,
@@ -401,8 +411,7 @@ def _update_req_from_rule_config(
401411
assignee = config.action.assignee
402412
user_id = None
403413
if assignee:
404-
users = get_active_users(
405-
user_service=self._user_service_stub,
414+
users = self._get_active_users(
406415
filter=f"name=='{assignee}'",
407416
)
408417
if not users:
@@ -453,8 +462,7 @@ def _update_req_from_rule_config(
453462

454463
# Validate channels are present within each asset
455464
for asset in assets:
456-
found_channels = get_channels(
457-
channel_service=self._channel_service_stub,
465+
found_channels = self._get_channels(
458466
filter=f"asset_id == '{asset.asset_id}' && {name_in}",
459467
)
460468
found_channels_names = [channel.name for channel in found_channels]
@@ -598,8 +606,35 @@ def _get_rule_from_rule_id(self, rule_id: str) -> Optional[Rule]:
598606
return None
599607

600608
def _get_assets(self, names: List[str] = [], ids: List[str] = []) -> List[Asset]:
609+
if self._enable_caching:
610+
return self._get_assets_cached(tuple(sorted(names)), tuple(sorted(ids)))
611+
else:
612+
return list_assets_impl(self._asset_service_stub, names, ids)
613+
614+
def _get_channels(self, filter: str) -> List[ChannelPb]:
615+
if self._enable_caching:
616+
return self._get_channels_cached(filter)
617+
else:
618+
return get_channels(channel_service=self._channel_service_stub, filter=filter)
619+
620+
def _get_active_users(self, filter: str) -> List[UserPb]:
621+
if self._enable_caching:
622+
return self._get_active_users_cached(filter)
623+
else:
624+
return get_active_users(user_service=self._user_service_stub, filter=filter)
625+
626+
@cache
627+
def _get_assets_cached(self, names: Tuple[str], ids: Tuple[str]) -> List[Asset]:
601628
return list_assets_impl(self._asset_service_stub, names, ids)
602629

630+
@cache
631+
def _get_channels_cached(self, filter: str) -> List[ChannelPb]:
632+
return get_channels(channel_service=self._channel_service_stub, filter=filter)
633+
634+
@cache
635+
def _get_active_users_cached(self, filter: str) -> List[UserPb]:
636+
return get_active_users(user_service=self._user_service_stub, filter=filter)
637+
603638

604639
@dataclass
605640
class RuleChannelReference:

python/lib/sift_py/rule_evaluation/service.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ class RuleEvaluationService:
4343
def __init__(self, channel: SiftChannel):
4444
self._channel = channel
4545
self._rule_evaluation_stub = RuleEvaluationServiceStub(channel)
46-
self._rule_service = RuleService(channel)
46+
47+
# Enable caching during rule evaluation. This service is typically
48+
# short lived in a workflow so assets, channels, and users are unlikely
49+
# to change during its lifetime to invalidate caches.
50+
self._rule_service = RuleService(channel, enable_caching=True)
4751

4852
def evaluate_against_run(
4953
self,

0 commit comments

Comments
 (0)