0

I have a simple python App Engine application with low traffic (3 hours of instance activity per day more or less). I'm using everything below the free tier provided and I have:

  • F1 Instances with auto-scaling
  • 1/2 MB of Memcache
  • I make "heavy" use of ndb.get_multi() (with 400 entities per request only for a small amount of requests, but these 400 entities weigh only 3MB)

The problem is that I get the Exceeded soft private memory limit of 128 MB with 131 MB after servicing 93 requests total error randomly once every 2/3 days but there is no request the app can't process singularly.

I've tried to call gc.collect() at the end of each request but the amount of memory keeps increasing event after servicing the request.

How can I solve this without upgrading to higher performing instances (F2)?

Thanks!

Federico Capello
  • 1,088
  • 3
  • 12
  • 21
  • 1
    Maybe of interest: https://stackoverflow.com/questions/45026920/when-will-memory-get-freed-after-completing-the-request-on-app-engine-backend-in/45061554#45061554. Since then I switched all the way to the F4 class (similar app usage pattern) and couldn't be happier: app's faster, no memory worries and still well in the free instance hours quota (you'd be using ~12 instance h/day at the same usage pattern). Maybe worth a try. – Dan Cornilescu May 24 '18 at 12:19
  • Thank you @DanCornilescu for the nice suggestion. But is the F4 included in the free quota? I read that only the F1 is provided – Federico Capello May 24 '18 at 16:32
  • 1
    The free quota is just an instance hours value (counted as F1!). 1h of F4 is counted as 4h of F1. See note at the end of [Standard environment instances](https://cloud.google.com/appengine/pricing#standard_instance_pricing). So if F4 runs for less than 28h/4 = ~6.25h per day it's free – Dan Cornilescu May 24 '18 at 16:45
  • Cool! I've just redeployed my app with F2 and I'll test how things go. Both your comment and Jeff's answer have been ultra helpful. Thank you so much – Federico Capello May 24 '18 at 16:48

1 Answers1

2

I suspect you are using tasks to process batches of 400 entities. There is a weird quirk (I would call it a bug but Google doesn't seem to think so) with the way that GAE handles memory cleanup with tasks. When the task completes, GAE does not clean up the cache right away, and if you are doing tasks on a regular basis, this can add up.

My solution was to define some entities like this:

class MyEntity(ndb.Model):
    _use_cache = False
    _use_memcache = False

You can also disable caching in the get_multi() call itself.

For the 400 entities you are processing, if you disable caching, it might fix the problem for you.

new name
  • 15,861
  • 19
  • 68
  • 114