Skip to content

Commit 7906144

Browse files
authored
LJ-474 Refactor privacy request processing to never re-use sessions (#5862)
1 parent 728a36a commit 7906144

File tree

3 files changed

+105
-48
lines changed

3 files changed

+105
-48
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
3030
- Bumped supported Python versions to `3.10.16` and `3.9.21` [#5840](https://github.com/ethyca/fides/pull/5840)
3131
- Update the privacy request detail page to a new layout and improved styling [#5824](https://github.com/ethyca/fides/pull/5824)
3232
- Updated privacy request handling to still succeed if not all identities are provided [#5836](https://github.com/ethyca/fides/pull/5836)
33+
- Refactored privacy request processing to never re-use sessions [#5862](https://github.com/ethyca/fides/pull/5862)
3334

3435

3536
### Developer Experience

src/fides/api/task/graph_task.py

+84-43
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
ConnectionType,
3737
)
3838
from fides.api.models.datasetconfig import DatasetConfig
39-
from fides.api.models.policy import Policy
39+
from fides.api.models.policy import Policy, Rule
40+
from fides.api.models.privacy_preference import PrivacyPreferenceHistory
4041
from fides.api.models.privacy_request import ExecutionLog, PrivacyRequest, RequestTask
4142
from fides.api.schemas.policy import ActionType, CurrentStep
4243
from fides.api.schemas.privacy_request import ExecutionLogStatus
@@ -54,7 +55,9 @@
5455
make_immutable,
5556
make_mutable,
5657
)
57-
from fides.api.util.consent_util import add_errored_system_status_for_consent_reporting
58+
from fides.api.util.consent_util import (
59+
add_errored_system_status_for_consent_reporting_on_preferences,
60+
)
5861
from fides.api.util.logger import Pii
5962
from fides.api.util.logger_context_utils import LoggerContextKeys
6063
from fides.api.util.saas_util import FIDESOPS_GROUPED_INPUTS
@@ -138,13 +141,7 @@ def result(*args: Any, **kwargs: Any) -> Any:
138141
self.resources.request.id,
139142
)
140143
self.log_skipped(action_type, exc)
141-
for pref in self.resources.request.privacy_preferences:
142-
# For consent reporting, also caching the given system as skipped for all historical privacy preferences.
143-
pref.cache_system_status(
144-
self.resources.session,
145-
self.connector.configuration.system_key,
146-
ExecutionLogStatus.skipped,
147-
)
144+
self.cache_system_status_for_preferences()
148145
return default_return
149146
except BaseException as ex: # pylint: disable=W0703
150147
traceback.print_exc()
@@ -164,11 +161,7 @@ def result(*args: Any, **kwargs: Any) -> Any:
164161
action_type.value
165162
] # Convert ActionType into a CurrentStep, no longer coerced with Pydantic V2
166163
)
167-
add_errored_system_status_for_consent_reporting(
168-
self.resources.session,
169-
self.resources.request,
170-
self.connector.configuration,
171-
)
164+
self.add_error_status_for_consent_reporting()
172165
if not self.request_task.id:
173166
# TODO Remove when we stop support for DSR 2.0
174167
# Re-raise to stop privacy request execution on failure for
@@ -730,6 +723,48 @@ def consent_request(self, identity: Dict[str, Any]) -> bool:
730723
self.log_end(ActionType.consent)
731724
return output
732725

726+
def cache_system_status_for_preferences(self) -> None:
727+
"""
728+
Calls cache_system_status for all historical privacy preferences for the given request.
729+
730+
Purposely uses a new session.
731+
"""
732+
733+
privacy_request_id = self.resources.request.id
734+
735+
with get_db() as db:
736+
737+
privacy_preferences = db.query(PrivacyPreferenceHistory).filter(
738+
PrivacyPreferenceHistory.privacy_request_id == privacy_request_id
739+
)
740+
for pref in privacy_preferences:
741+
# For consent reporting, also caching the given system as skipped for all historical privacy preferences.
742+
pref.cache_system_status(
743+
db,
744+
self.connector.configuration.system_key, # type: ignore[arg-type]
745+
ExecutionLogStatus.skipped,
746+
)
747+
748+
def add_error_status_for_consent_reporting(self) -> None:
749+
"""
750+
Adds the errored system status for all historical privacy preferences for the given request that
751+
are deemed relevant for the connector failure (i.e if they had a "pending" log added to them).
752+
753+
Purposely uses a new session.
754+
"""
755+
privacy_request_id = self.resources.request.id
756+
with get_db() as db:
757+
privacy_preferences = (
758+
db.query(PrivacyPreferenceHistory)
759+
.filter(
760+
PrivacyPreferenceHistory.privacy_request_id == privacy_request_id
761+
)
762+
.all()
763+
)
764+
add_errored_system_status_for_consent_reporting_on_preferences(
765+
db, privacy_preferences, self.connector.configuration
766+
)
767+
733768

734769
def collect_queries(
735770
traversal: Traversal, resources: TaskResources
@@ -816,39 +851,45 @@ def build_affected_field_logs(
816851
}]
817852
"""
818853

819-
targeted_field_paths: Dict[FieldAddress, str] = {}
854+
policy_id = policy.id
820855

821-
for rule in policy.rules: # type: ignore[attr-defined]
822-
if rule.action_type != action_type:
823-
continue
824-
rule_categories: List[str] = rule.get_target_data_categories()
825-
if not rule_categories:
826-
continue
856+
with get_db() as db:
827857

828-
collection_categories: Dict[
829-
str, List[FieldPath]
830-
] = node.collection.field_paths_by_category # type: ignore
831-
for rule_cat in rule_categories:
832-
for collection_cat, field_paths in collection_categories.items():
833-
if collection_cat.startswith(rule_cat):
834-
targeted_field_paths.update(
835-
{
836-
node.address.field_address(field_path): collection_cat
837-
for field_path in field_paths
838-
}
839-
)
858+
rules = db.query(Rule).filter(Rule.policy_id == policy_id)
840859

841-
ret: List[Dict[str, Any]] = []
842-
for field_address, data_categories in targeted_field_paths.items():
843-
ret.append(
844-
{
845-
"path": field_address.value,
846-
"field_name": field_address.field_path.string_path,
847-
"data_categories": [data_categories],
848-
}
849-
)
860+
targeted_field_paths: Dict[FieldAddress, str] = {}
861+
862+
for rule in rules: # type: ignore[attr-defined]
863+
if rule.action_type != action_type:
864+
continue
865+
rule_categories: List[str] = rule.get_target_data_categories()
866+
if not rule_categories:
867+
continue
868+
869+
collection_categories: Dict[
870+
str, List[FieldPath]
871+
] = node.collection.field_paths_by_category # type: ignore
872+
for rule_cat in rule_categories:
873+
for collection_cat, field_paths in collection_categories.items():
874+
if collection_cat.startswith(rule_cat):
875+
targeted_field_paths.update(
876+
{
877+
node.address.field_address(field_path): collection_cat
878+
for field_path in field_paths
879+
}
880+
)
881+
882+
ret: List[Dict[str, Any]] = []
883+
for field_address, data_categories in targeted_field_paths.items():
884+
ret.append(
885+
{
886+
"path": field_address.value,
887+
"field_name": field_address.field_path.string_path,
888+
"data_categories": [data_categories],
889+
}
890+
)
850891

851-
return ret
892+
return ret
852893

853894

854895
def build_consent_dataset_graph(datasets: List[DatasetConfig]) -> DatasetGraph:

src/fides/api/util/consent_util.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,30 @@ def add_errored_system_status_for_consent_reporting(
214214
215215
Deeming them relevant if they already had a "pending" log added to them.
216216
"""
217-
for pref in privacy_request.privacy_preferences: # type: ignore[attr-defined]
217+
add_errored_system_status_for_consent_reporting_on_preferences(db, privacy_request.privacy_preferences, connection_config) # type: ignore[attr-defined]
218+
219+
220+
def add_errored_system_status_for_consent_reporting_on_preferences(
221+
db: Session,
222+
privacy_preferences: List[PrivacyPreferenceHistory],
223+
connection_config: ConnectionConfig,
224+
) -> None:
225+
"""
226+
Cache an errored system status for consent reporting on just the subset
227+
of preferences that were deemed relevant for the connector on failure,
228+
from the provided list of preferences.
229+
230+
Deeming them relevant if they already had a "pending" log added to them.
231+
"""
232+
for preference in privacy_preferences:
218233
if (
219-
pref.affected_system_status
220-
and pref.affected_system_status.get(connection_config.system_key)
234+
preference.affected_system_status
235+
and preference.affected_system_status.get(connection_config.system_key)
221236
== ExecutionLogStatus.pending.value
222237
):
223-
pref.cache_system_status(
238+
preference.cache_system_status(
224239
db,
225-
connection_config.system_key,
240+
connection_config.system_key, # type: ignore[arg-type]
226241
ExecutionLogStatus.error,
227242
)
228243

0 commit comments

Comments
 (0)