Skip to content

InMemoryBackingStore infinite loop #954

@Falven

Description

@Falven

Describe the bug

The InMemoryBackingStore class is experiencing an infinite loop when setting values. This occurs because the set method subscribes a lambda function that calls set again, which in turn triggers the subscription callback, causing set to be called repeatedly.

        if isinstance(value, list):
            # if its a collection, subscribe to the collection's item BackingStores and use
            # the events to flag the collection property is "dirty"
            for item in value:
                if isinstance(item, BackedModel) and item.backing_store:
                    item.backing_store.is_initialization_completed = True
                    item.backing_store.subscribe(
                        lambda prop_key, old_val, new_val: self.set(key, value)
                    )

        self.__store[key] = value_to_add
        for sub in list(self.__subscriptions):
            self.__subscriptions[sub](key, old_value, value_to_add)

Because you're invoking the subscription which is calling set which is invoking the subscription.

Expected behavior

The set method should store the value and notify subscribers without causing an infinite loop.

How to reproduce

  1. Create an instance of InMemoryBackingStore.
  2. Set a value that is a BackedModel or a list containing BackedModel instances.
  3. The set method subscribes a lambda function that calls set again.
  4. The subscription callback is triggered, causing set to be called repeatedly.

SDK Version

No response

Latest version known to work for scenario above?

No response

Known Workarounds

Awful, but until an update, unsubscribing and re-subscribing around problematic code.

subscription_ids = []

# Collect all backing stores and sub ids as to not modify while iterating
for role in app.app_roles:
    if isinstance(role, BackedModel) and role.backing_store:
        for (
            sub_id,
            callback,
        ) in role.backing_store._InMemoryBackingStore__subscriptions.items():
            if callback.__name__ == "<lambda>":
                subscription_ids.append((role.backing_store, sub_id))

# Unsubscribe lambdas...
for backing_store, sub_id in subscription_ids:
    backing_store.unsubscribe(sub_id)

# Problematic code
for role in app.app_roles:
    if role.is_enabled != enable:
        role.is_enabled = enable

# Resubscribe lambdas...
for backing_store, sub_id in subscription_ids:
    backing_store.subscribe(
        lambda prop_key, old_val, new_val: role.backing_store.set(
            prop_key, new_val
        ),
        sub_id,
    )

Debug output

Click to expand log ```
</details>


### Configuration

_No response_

### Other information

_No response_

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:backing-storeFocused on functional modules of the productpriority:p1High priority/Major issue but not blocking or Big percentage of customers affected.Bug SLA <=7daystype:bugA broken experience

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions