Skip to content

Commit 6ea8d6e

Browse files
authored
Merge pull request #945 from hubmapconsortium/yuanzhou/cache-exclude
Fix cache handling on skipped/excluded properties
2 parents 1e8e1cd + 4371f5f commit 6ea8d6e

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.6.3
1+
2.6.4

src/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ def get_entity_by_id(id):
840840
except Exception as e:
841841
internal_server_error(e)
842842

843-
# Get the generated complete entity result from cache if exists
843+
# Get the generated complete entity result from cache (only when NO skipped properties) if exists
844844
# Otherwise re-generate on the fly
845845
# NOTE: top-level properties in `triggered_top_props_to_skip` will skip the trigger methods
846846
# Nested properties like `direct_ancestors.files` will be handled by the trigger method - Zhou 10/1/2025

src/schema/schema_manager.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -851,11 +851,10 @@ def get_complete_entity_result(request, token, entity_dict, properties_to_skip =
851851
cache_key = f'{_memcached_prefix}_complete_{entity_uuid}'
852852
cache_result = _memcached_client.get(cache_key)
853853

854-
# Use the cached data if found and still valid
855-
# Otherwise, calculate and add to cache
856-
if cache_result is None:
857-
if _memcached_client and _memcached_prefix:
858-
logger.info(f'Cache of complete entity of {entity_type} {entity_uuid} not found or expired at time {datetime.now()}')
854+
# As long as `properties_to_skip` is specified (including when`?exclude` is used in query parameter)
855+
# Do not return the cached data and store the new cache regardless of it's available or not - Zhou 10/10/2025
856+
if properties_to_skip:
857+
logger.info(f'Skipped/excluded properties specified in get_complete_entity_result(). Always generate the {TriggerTypeEnum.ON_READ} data and do not cache the result.')
859858

860859
# No error handling here since if a 'on_read_trigger' method fails,
861860
# the property value will be the error message
@@ -873,22 +872,47 @@ def get_complete_entity_result(request, token, entity_dict, properties_to_skip =
873872

874873
# Remove properties of None value
875874
complete_entity = remove_none_values(complete_entity_dict)
875+
else:
876+
logger.info('Skipped/excluded properties NOT specified in get_complete_entity_result()')
877+
878+
# Re-generate the triggered data and add to memcache
879+
# Otherwise, use the cached data if found and still valid
880+
if cache_result is None:
881+
if _memcached_client and _memcached_prefix:
882+
logger.info(f'Cache of complete entity of {entity_type} {entity_uuid} not found or expired at time {datetime.now()}')
883+
884+
# No error handling here since if a 'on_read_trigger' method fails,
885+
# the property value will be the error message
886+
# Pass {} since no new_data_dict for 'on_read_trigger'
887+
generated_on_read_trigger_data_dict = generate_triggered_data( trigger_type=TriggerTypeEnum.ON_READ
888+
, normalized_class=entity_type
889+
, request=request
890+
, user_token=token
891+
, existing_data_dict=entity_dict
892+
, new_data_dict={}
893+
, properties_to_skip=properties_to_skip)
876894

877-
# Need both client and prefix when creating the cache
878-
# Do NOT cache when properties_to_skip is specified
879-
if _memcached_client and _memcached_prefix and (not properties_to_skip):
880-
logger.info(f'Creating complete entity cache of {entity_type} {entity_uuid} at time {datetime.now()}')
895+
# Merge the entity info and the generated on read data into one dictionary
896+
complete_entity_dict = {**entity_dict, **generated_on_read_trigger_data_dict}
881897

882-
cache_key = f'{_memcached_prefix}_complete_{entity_uuid}'
883-
_memcached_client.set(cache_key, complete_entity, expire = SchemaConstants.MEMCACHED_TTL)
898+
# Remove properties of None value
899+
complete_entity = remove_none_values(complete_entity_dict)
884900

885-
logger.debug(f"Following is the complete {entity_type} cache created at time {datetime.now()} using key {cache_key}:")
886-
logger.debug(complete_entity)
887-
else:
888-
logger.info(f'Using complete entity cache of {entity_type} {entity_uuid} at time {datetime.now()}')
889-
logger.debug(cache_result)
901+
# Need both client and prefix when creating the cache
902+
# Do NOT cache when properties_to_skip is specified
903+
if _memcached_client and _memcached_prefix and (not properties_to_skip):
904+
logger.info(f'Creating complete entity cache of {entity_type} {entity_uuid} at time {datetime.now()}')
905+
906+
cache_key = f'{_memcached_prefix}_complete_{entity_uuid}'
907+
_memcached_client.set(cache_key, complete_entity, expire = SchemaConstants.MEMCACHED_TTL)
908+
909+
logger.debug(f"Following is the complete {entity_type} cache created at time {datetime.now()} using key {cache_key}:")
910+
logger.debug(complete_entity)
911+
else:
912+
logger.info(f'Using complete entity cache of {entity_type} {entity_uuid} at time {datetime.now()}')
913+
logger.debug(cache_result)
890914

891-
complete_entity = cache_result
915+
complete_entity = cache_result
892916
else:
893917
# Just return the original entity_dict otherwise
894918
complete_entity = entity_dict

0 commit comments

Comments
 (0)