Skip to content

Instantly share code, notes, and snippets.

@mikelambert
Created February 28, 2015 09:58
Show Gist options
  • Save mikelambert/6615b37fa326c1008a4b to your computer and use it in GitHub Desktop.
Save mikelambert/6615b37fa326c1008a4b to your computer and use it in GitHub Desktop.
A hacky attempt to fix the RPC starvation problems I encountered with the NDB eventloops.
# This attempts to force a FIFO ordering on RPC execution in the eventloop (as opposed to random RPC execution)
RPC_ORDERING = True
if RPC_ORDERING:
import collections
from google.appengine.ext.ndb import eventloop
class OrderedEventLoop(eventloop.EventLoop):
def __init__(self):
super(OrderedEventLoop, self).__init__()
self.rpcs = collections.OrderedDict()
eventloop.EventLoop = OrderedEventLoop
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import apiproxy_rpc
@classmethod
def __check_one(cls, rpcs):
rpc = None
logging.debug('Pending RPCs: %s', rpcs)
for rpc in rpcs:
assert isinstance(rpc, cls), repr(rpc)
# Original:
# state = rpc.__rpc.state
# Revised:
state = rpc.state
if state == apiproxy_rpc.RPC.FINISHING:
# Original:
# rpc.__call_user_callback()
# Revised:
rpc.wait()
logging.debug('Found finished RPC: %s', rpc)
return rpc, None
assert state != apiproxy_rpc.RPC.IDLE, repr(rpc)
logging.debug('No finished RPCs, going to wait for first RPC: %s', rpcs[0])
# This is the important changed line in this whole function:
# We want to return the oldest RPC to execute, not a random one.
return None, rpcs[0]
assert hasattr(apiproxy_stub_map.UserRPC, '_UserRPC__check_one')
apiproxy_stub_map.UserRPC._UserRPC__check_one = __check_one
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment