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

Stream JSON responses #164

Merged
merged 9 commits into from
Jan 30, 2015
Merged

Stream JSON responses #164

merged 9 commits into from
Jan 30, 2015

Conversation

dracos
Copy link
Member

@dracos dracos commented Jan 28, 2015

When we start, we have an iterable QuerySet. So this changes add_codes to be iterable, passes an iterdict [1] rather than a dict to output_json, changes output_json to use a StreamingHttpResponse by default, and updates the callback middleware to work with streaming or non-streaming responses. This hopefully reduces memory usage for one particular request from c. 2Gb to 200Mb. Similarly for output_html, we keep everything as an iterable, doing something horrible with a template in order to put our iteration in the middle.

[1] An iterdict is a dict subclass that does nothing but provide an iterable for items/iteritems, in order so that the json package will think it's a dictionary, iterate over it and output an iterator. Otherwise we'd need to load everything into a dictionary in memory to iterate it all back out...

@dracos
Copy link
Member Author

dracos commented Jan 29, 2015

Note that:

@dracos dracos force-pushed the stream-responses branch 2 times, most recently from 9ebcbdd to 0466f06 Compare January 29, 2015 15:32
def output_html(request, title, areas, **kwargs):
kwargs['json_url'] = request.get_full_path().replace('.html', '')
kwargs['title'] = title
kwargs['areas'] = sorted_areas(areas)
kwargs['indent_areas'] = kwargs.get('indent_areas', False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't this the line you decided to chop?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but then I need to pass it in the template_area iterator so thought I might as well leave it for that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it doesn't need to be in kwargs so changed for the below.

@davea
Copy link
Member

davea commented Jan 30, 2015

Aside from those little inline comments, 👍

Create an iterator of the callback header, content, and footer.
Both HttpResponse and StreamingHttpResponse handle this fine.
We subclass dict so that we can create an iterator that json will use.
This works around https://code.djangoproject.com/ticket/24240 which
otherwise dies when trying to cope with a StreamingHttpResponse
containing unicode strings.
This works around https://code.djangoproject.com/ticket/24242 so that
gzipped streamed responses aren't larger than the original content.
It does this in quite a horrible way, by putting a flag in the template,
and then inserting the iterable of areas in place of that flag. Also
make sure we cache template loading.

Thanks to Dave Arter for the defaultiter implementation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants