Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetching an entity recursive builds forever - hanging forever #82

Open
hero-kieran opened this issue Jun 7, 2023 · 0 comments
Open

Comments

@hero-kieran
Copy link

When trying to fetch an entity via

workout = self.client.entry(workout_id)

The program hung and continued to grow in memory usage. The id put in the URL of contentful entity and it appears just fine.

Looking into the code I've found that the call to build which is called from the _get function is the recursive issue in resource_builder.py. It will unpack everything in the entity and try to build its descendants.

In this instance, the entity has a link to similar workouts entities which may recursively link back to the original entity which I believe is the likely cause of this problem.

Though this obviously isn't an issue on the website, and is totally permitted behavior.

There looks like there are things in place to detect the depth of entities being built to try and address this issue but obviously there is a bug in this code and it fails to do so, or exit with exception.

In the order of execution build is called first and _build_array is run, and then subsequently, _build_single() is called over and over again.

Courting the number of times the original id appears in the ids list, I can see that it appear 7 times in the first 100 runs of the build single.

def build(self):
        """Creates the objects from the JSON response"""

        if self.json['sys']['type'] == 'Array':
            if any(k in self.json for k in ['nextSyncUrl', 'nextPageUrl']):
                print('sync page')
                return SyncPage(
                    self.json,
                    default_locale=self.default_locale,
                    localized=True
                )
            print('build array')
            return self._build_array()
        print('build single')
        return self._build_single()

    def _build_single(self):
        includes = []
        errors = []
        if self.includes_for_single is not None:
            includes = self.includes_for_single
        if self.errors_for_single is not None:
            errors = self.errors_for_single

        return self._build_item(
            self.json,
            includes=includes,
            errors=errors
        )

    def _build_array(self):

        includes = self._includes()
        print('build includes')
        errors = self._errors()
        print('build errors')

        items = [self._build_item(
                    item,
                    includes=includes,
                    errors=errors
                 ) for item in self.json['items']
                 if not unresolvable(item, self._errors())]

        print('build array items')

        return Array(self.json, items)


    ids = list()

    def _build_item(self, item, includes=None, errors=None):
        print(f'building item {item}')
        if includes is None:
            includes = []
        if errors is None:
            errors = []

        buildables = {
            'Entry': Entry,
            'Asset': Asset,
            'ContentType': ContentType,
            'Space': Space,
            'DeletedEntry': DeletedEntry,
            'DeletedAsset': DeletedAsset,
            'Locale': Locale
        }


        print(self.reuse_entries)
        resource = self._resource_from_cache(item) if self.reuse_entries else None
        if resource is not None:
            return resource

        print('cache')

        if item['sys']['type'] in buildables:

            print('check item', item)
            self.ids.append(item['sys']['id'])
            if len(self.ids) > 100:
                print(self.ids)
                s = set(self.ids)
                print(len(s), s)

                exit()

            return buildables[item['sys']['type']](
                item,
                default_locale=self.default_locale,
                localized=self.localized,
                includes=includes,
                errors=errors,
                resources=self.resources,
                depth=self.depth,
                max_depth=self.max_depth
            )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant