Esempio n. 1
0
 def setUp(self):
     super(FanInMergeJoinDispatchTest, self).setUp()
     setUpByString(self, FAN_IN_MACHINE, machineName='FanInMachine', instanceName='foo')
     mock('config.currentConfiguration', returns=self.currentConfig, tracker=None)
     for i in range(20):
         SimpleModel(key_name='%d' % i).put()
     memcache.set('calls', 0)
     memcache.set('raise', False)
     
     context = self.factory.createFSMInstance(self.machineConfig.name, instanceName='foo')
     context[constants.STEPS_PARAM] = 1
     obj = TemporaryStateObject()
     obj[constants.TASK_NAME_PARAM] = 'taskName'
     obj[constants.RETRY_COUNT_PARAM] = 0
     
     self.context = None
     self.obj = None
     
     random.seed(0)
     context.dispatch('pseudo-init', obj) # write down a work package
     self.index = context[constants.INDEX_PARAM]
     
     self.assertEqual(1, _FantasmFanIn.all().count())
     self.assertEqual('foo--InitialState--ok--FanInState--step-2-2957927341', 
                      _FantasmFanIn.all().get().workIndex)
Esempio n. 2
0
    def setUp(self):
        super(FanInMergeJoinDispatchTest, self).setUp()
        setUpByString(self,
                      FAN_IN_MACHINE,
                      machineName='FanInMachine',
                      instanceName='foo')
        mock('config.currentConfiguration',
             returns=self.currentConfig,
             tracker=None)
        for i in range(20):
            SimpleModel(key_name='%d' % i).put()
        memcache.set('calls', 0)
        memcache.set('raise', False)

        context = self.factory.createFSMInstance(self.machineConfig.name,
                                                 instanceName='foo')
        context[constants.STEPS_PARAM] = 1
        obj = TemporaryStateObject()
        obj[constants.TASK_NAME_PARAM] = 'taskName'
        obj[constants.RETRY_COUNT_PARAM] = 0

        self.context = None
        self.obj = None

        random.seed(0)
        context.dispatch('pseudo-init', obj)  # write down a work package
        self.index = context[constants.INDEX_PARAM]

        self.assertEqual(1, _FantasmFanIn.all().count())
        self.assertEqual(
            'foo--InitialState--ok--FanInState--step-2-2957927341',
            _FantasmFanIn.all().get().workIndex)
Esempio n. 3
0
 def test_DatastoreFSMContinuationFanIn_work_packages_restored_on_exception(self):
     
     obj = TemporaryStateObject()
     obj[TASK_NAME_PARAM] = 'taskName'
     obj[RETRY_COUNT_PARAM] = 0
     
     event = self.context.initialize()
     self.assertTrue(FSM.PSEUDO_INIT, self.context.currentState.name)
     self.assertFalse(self.context.currentState.isContinuation)
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-initial', self.context.currentState.name)
     self.assertEqual(0, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-continuation', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
     
     # override the action of the transition raise an exception
     originalAction = self.context.currentState.getTransition(event).action
     try:
         self.context.currentState.getTransition(event).action = RaiseExceptionAction()
         self.assertRaises(Exception, self.context.dispatch, event, obj)
         self.assertEqual('state-continuation', self.context.currentState.name)
         self.assertEqual(1, _FantasmFanIn.all().count()) # the work packages are restored on exception
     finally:
         self.context.currentState.getTransition(event).action = originalAction # and restore
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-fan-in', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-final', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 4
0
 def test_mergeJoinDispatch_1234_contexts(self):
     for i in xrange(1234):
         _FantasmFanIn(workIndex='instanceName--foo--event--foo2--step-0-2654435761').put()
     self.assertEqual(1000, _FantasmFanIn.all().count()) # can't get them all with .count()
     contexts = self.context.mergeJoinDispatch('event', {RETRY_COUNT_PARAM: 0})
     self.assertEqual(1234, len(contexts))
     self.assertEqual(1000, _FantasmFanIn.all().count())
Esempio n. 5
0
 def test_mergeJoinDispatch_1_context(self):
     _FantasmFanIn(
         workIndex='instanceName--foo--event--foo2--step-0-2654435761').put(
         )
     self.assertEqual(1, _FantasmFanIn.all().count())
     contexts = self.context.mergeJoinDispatch('event',
                                               {RETRY_COUNT_PARAM: 0})
     self.assertEqual([{'__ix__': 1, '__step__': 0}], contexts)
     self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 6
0
 def test_mergeJoinDispatch_1234_contexts(self):
     for i in xrange(1234):
         _FantasmFanIn(
             workIndex='instanceName--foo--event--foo2--step-0-2654435761'
         ).put()
     self.assertEqual(
         1000,
         _FantasmFanIn.all().count())  # can't get them all with .count()
     contexts = self.context.mergeJoinDispatch('event',
                                               {RETRY_COUNT_PARAM: 0})
     self.assertEqual(1234, len(contexts))
     self.assertEqual(1000, _FantasmFanIn.all().count())
Esempio n. 7
0
 def test_fail_at_acquireWriteLock(self):
     self.setUpContext()
     mock('ReadWriteLock.acquireWriteLock', raises=Exception, tracker=None)
     self.assertRaises(Exception, self.context.dispatch, 'pseudo-init', self.obj)
     self.assertEqual(0, _FantasmFanIn.all().count())
     self.assertEqual(None, memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
     restore()
     
     self.setUpContext(retryCount=1)
     self.context.dispatch('pseudo-init', self.obj)
     self.assertEqual(1, _FantasmFanIn.all().count())
     self.assertEqual('foo--InitialState--ok--FanInState--step-2-2957927341', 
                      _FantasmFanIn.all().get().workIndex)
     self.assertEqual('65536', memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 8
0
 def test_run_twice(self):
     self.setUpContext()
     self.context.dispatch('pseudo-init', self.obj)
     self.assertEqual(1, _FantasmFanIn.all().count())
     self.assertEqual('foo--InitialState--ok--FanInState--step-2-2957927341', 
                      _FantasmFanIn.all().get().workIndex)
     self.assertEqual('65536', memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
     
     self.setUpContext()
     self.context.dispatch('pseudo-init', self.obj)
     self.assertEqual(1, _FantasmFanIn.all().count())
     self.assertEqual('foo--InitialState--ok--FanInState--step-2-2957927341', 
                      _FantasmFanIn.all().get().workIndex)
     self.assertEqual('65536', memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 9
0
    def test_fail_at_put(self):
        self.setUpContext()
        mock('db.put', raises=Exception, tracker=None)
        self.assertRaises(Exception, self.context.dispatch, 'pseudo-init', copy.copy(self.obj))
        self.assertEqual(0, _FantasmFanIn.all(namespace='').count())
        # notice the +1 extra on the lock
        self.assertEqual(65537, memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
        restore()

        self.setUpContext(retryCount=1)
        self.context.dispatch('pseudo-init', self.obj)
        self.assertEqual(1, _FantasmFanIn.all(namespace='').count())
        self.assertEqual('foo--InitialState--ok--FanInState--step-2-2957927341',
                         _FantasmFanIn.all(namespace='').get().workIndex)
        self.assertEqual(65537, memcache.get('foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 10
0
    def mergeJoinDispatch(self, event, obj):
        """ Performs a merge join on the pending fan-in dispatches.

        @param event: an event that is being merge joined (destination state must be a fan in)
        @return: a list (possibly empty) of FSMContext instances
        """
        # this assertion comes from _queueDispatchFanIn - we never want fan-out info in a fan-in context
        assert not self.get(constants.GEN_PARAM)
        assert not self.get(constants.FORK_PARAM)

        # the work package index is stored in the url of the Task/FSMContext
        index = self.get(constants.INDEX_PARAM)
        self.logger.debug('Index: %s', index)
        taskNameBase = self.getTaskName(event, fanIn=True)

        # see comment (***) in self._queueDispatchFanIn
        #
        # in the case of failing to acquire a read lock (due to failed release of write lock)
        # we have decided to keep retrying
        raiseOnFail = False
        if self._getTaskRetryLimit() is not None:
            raiseOnFail = (self._getTaskRetryLimit() > self.__obj[constants.RETRY_COUNT_PARAM])

        rwlock = ReadWriteLock(taskNameBase, self)
        rwlock.acquireReadLock(index, raiseOnFail=raiseOnFail)

        # and return the FSMContexts list
        class FSMContextList(list):
            """ A list that supports .logger.info(), .logger.warning() etc.for fan-in actions """
            def __init__(self, context, contexts, guarded=False):
                """ setup a self.logger for fan-in actions """
                super(FSMContextList, self).__init__(contexts)
                self.logger = Logger(context)
                self.instanceName = context.instanceName
                self.guarded = guarded

        # see comment (A) in self._queueDispatchFanIn(...)
        time.sleep(constants.DATASTORE_ASYNCRONOUS_INDEX_WRITE_WAIT_TIME)

        # the following step ensure that fan-in only ever operates one time over a list of data
        # the entity is created in State.dispatch(...) _after_ all the actions have executed
        # successfully
        khash = knuthHash(index)
        self.logger.debug('knuthHash of index: %s', khash)
        workIndex = '%s-%d' % (taskNameBase, khash)
        if obj[constants.RETRY_COUNT_PARAM] > 0:
            semaphore = RunOnceSemaphore(workIndex, self)
            if semaphore.readRunOnceSemaphore(payload=self.__obj[constants.TASK_NAME_PARAM]):
                self.logger.info("Fan-in idempotency guard for workIndex '%s', not processing any work items.",
                                 workIndex)
                return FSMContextList(self, [], guarded=True) # don't operate over the data again

        # fetch all the work packages in the current group for processing
        query = _FantasmFanIn.all(namespace='') \
                             .filter('workIndex =', workIndex) \
                             .order('__key__')

        # construct a list of FSMContexts
        contexts = [self.clone(replaceData=r.context) for r in query]
        return FSMContextList(self, contexts)
Esempio n. 11
0
 def test_batchsize_10(self):
     self.context['batchsize'] = 10
     self.context.initialize() # queues the first task
     runQueuedTasks(maxRetries=0)
     self.assertEqual(1 + self.EXTRA_COUNT, _FantasmFanIn.all().count())
     self.assertEqual(self.EXTRA_VALUES + self.EXPECTED_VALUES, 
                      sorted(ContinuationFanInResult.get_by_key_name('test').values))
Esempio n. 12
0
    def mergeJoinDispatch(self, event, obj):
        """ Performs a merge join on the pending fan-in dispatches.
        
        @param event: an event that is being merge joined (destination state must be a fan in) 
        @return: a list (possibly empty) of FSMContext instances
        """
        # this assertion comes from _queueDispatchFanIn - we never want fan-out info in a fan-in context
        assert not self.get(constants.GEN_PARAM)
        assert not self.get(constants.FORK_PARAM)

        # the work package index is stored in the url of the Task/FSMContext
        index = self.get(constants.INDEX_PARAM)
        taskNameBase = self.getTaskName(event, fanIn=True)

        # see comment (***) in self._queueDispatchFanIn
        #
        # in the case of failing to acquire a read lock (due to failed release of write lock)
        # we have decided to keep retrying
        raiseOnFail = False
        if self._getTaskRetryLimit() is not None:
            raiseOnFail = (self._getTaskRetryLimit() >
                           self.__obj[constants.RETRY_COUNT_PARAM])

        rwlock = ReadWriteLock(taskNameBase, self)
        rwlock.acquireReadLock(index, raiseOnFail=raiseOnFail)

        # and return the FSMContexts list
        class FSMContextList(list):
            """ A list that supports .logger.info(), .logger.warning() etc.for fan-in actions """
            def __init__(self, context, contexts):
                """ setup a self.logger for fan-in actions """
                super(FSMContextList, self).__init__(contexts)
                self.logger = Logger(context)
                self.instanceName = context.instanceName

        # see comment (A) in self._queueDispatchFanIn(...)
        time.sleep(constants.DATASTORE_ASYNCRONOUS_INDEX_WRITE_WAIT_TIME)

        # the following step ensure that fan-in only ever operates one time over a list of data
        # the entity is created in State.dispatch(...) _after_ all the actions have executed
        # successfully
        workIndex = '%s-%d' % (taskNameBase, knuthHash(index))
        if obj[constants.RETRY_COUNT_PARAM] > 0:
            semaphore = RunOnceSemaphore(workIndex, self)
            if semaphore.readRunOnceSemaphore(
                    payload=self.__obj[constants.TASK_NAME_PARAM]):
                self.logger.info(
                    "Fan-in idempotency guard for workIndex '%s', not processing any work items.",
                    workIndex)
                return FSMContextList(self,
                                      [])  # don't operate over the data again

        # fetch all the work packages in the current group for processing
        query = _FantasmFanIn.all() \
                             .filter('workIndex =', workIndex) \
                             .order('__key__')

        # construct a list of FSMContexts
        contexts = [self.clone(data=r.context) for r in query]
        return FSMContextList(self, contexts)
Esempio n. 13
0
 def test_batchsize_11(self):
     self.context['batchsize'] = 11
     self.context.initialize()  # queues the first task
     runQueuedTasks(maxRetries=0)
     self.assertEqual(1, _FantasmFanIn.all(namespace='').count())
     self.assertEqual(
         self.EXPECTED_VALUES,
         sorted(ContinuationFanInResult.get_by_key_name('test').values))
Esempio n. 14
0
 def test_batchsize_3(self):
     self.context['batchsize'] = 3
     self.context.initialize()  # queues the first task
     runQueuedTasks()
     self.assertEqual(4, _FantasmFanIn.all().count())
     self.assertEqual(
         self.EXPECTED_VALUES,
         sorted(ContinuationFanInResult.get_by_key_name('test').values))
Esempio n. 15
0
 def test_DatastoreFSMContinuationFanIn_smoke_test(self):
     event = self.context.initialize()
     self.assertTrue(FSM.PSEUDO_INIT, self.context.currentState.name)
     self.assertFalse(self.context.currentState.isContinuation)
     
     event = self.context.dispatch(event, TemporaryStateObject())
     self.assertEqual('state-initial', self.context.currentState.name)
     self.assertEqual(0, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, TemporaryStateObject())
     self.assertEqual('state-continuation', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, TemporaryStateObject())
     self.assertEqual('state-fan-in', self.context.currentState.name)
     self.assertEqual(0, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, TemporaryStateObject())
     self.assertEqual('state-final', self.context.currentState.name)
     self.assertEqual(0, _FantasmFanIn.all().count())
Esempio n. 16
0
    def test_DatastoreFSMContinuationFanIn_work_packages_restored_on_exception(
            self):

        obj = TemporaryStateObject()
        obj[TASK_NAME_PARAM] = 'taskName'
        obj[RETRY_COUNT_PARAM] = 0

        event = self.context.initialize()
        self.assertTrue(FSM.PSEUDO_INIT, self.context.currentState.name)
        self.assertFalse(self.context.currentState.isContinuation)

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-initial', self.context.currentState.name)
        self.assertEqual(0, _FantasmFanIn.all().count())

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-continuation', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())

        # override the action of the transition raise an exception
        originalAction = self.context.currentState.getTransition(event).action
        try:
            self.context.currentState.getTransition(
                event).action = RaiseExceptionAction()
            self.assertRaises(Exception, self.context.dispatch, event, obj)
            self.assertEqual('state-continuation',
                             self.context.currentState.name)
            self.assertEqual(1,
                             _FantasmFanIn.all().count()
                             )  # the work packages are restored on exception
        finally:
            self.context.currentState.getTransition(
                event).action = originalAction  # and restore

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-fan-in', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-final', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 17
0
    def test_fail_at_acquireWriteLock(self):
        self.setUpContext()
        mock('ReadWriteLock.acquireWriteLock', raises=Exception, tracker=None)
        self.assertRaises(Exception, self.context.dispatch, 'pseudo-init',
                          self.obj)
        self.assertEqual(0, _FantasmFanIn.all().count())
        self.assertEqual(
            None,
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
        restore()

        self.setUpContext(retryCount=1)
        self.context.dispatch('pseudo-init', self.obj)
        self.assertEqual(1, _FantasmFanIn.all().count())
        self.assertEqual(
            'foo--InitialState--ok--FanInState--step-2-2957927341',
            _FantasmFanIn.all().get().workIndex)
        self.assertEqual(
            '65536',
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 18
0
    def test_run_twice(self):
        self.setUpContext()
        self.context.dispatch('pseudo-init', self.obj)
        self.assertEqual(1, _FantasmFanIn.all().count())
        self.assertEqual(
            'foo--InitialState--ok--FanInState--step-2-2957927341',
            _FantasmFanIn.all().get().workIndex)
        self.assertEqual(
            '65536',
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))

        self.setUpContext()
        self.context.dispatch('pseudo-init', self.obj)
        self.assertEqual(1, _FantasmFanIn.all().count())
        self.assertEqual(
            'foo--InitialState--ok--FanInState--step-2-2957927341',
            _FantasmFanIn.all().get().workIndex)
        self.assertEqual(
            '65536',
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 19
0
    def test_fail_at_put(self):
        self.setUpContext()
        mock('db.put', raises=Exception, tracker=None)
        self.assertRaises(Exception, self.context.dispatch, 'pseudo-init',
                          copy.copy(self.obj))
        self.assertEqual(0, _FantasmFanIn.all().count())
        # notice the +1 extra on the lock
        self.assertEqual(
            '65537',
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
        restore()

        self.setUpContext(retryCount=1)
        self.context.dispatch('pseudo-init', self.obj)
        self.assertEqual(1, _FantasmFanIn.all().count())
        self.assertEqual(
            'foo--InitialState--ok--FanInState--step-2-2957927341',
            _FantasmFanIn.all().get().workIndex)
        self.assertEqual(
            '65537',
            memcache.get(
                'foo--InitialState--ok--FanInState--step-2-lock-3255389373'))
Esempio n. 20
0
    def test_DatastoreFSMContinuationFanIn_smoke_test(self):
        event = self.context.initialize()
        self.assertTrue(FSM.PSEUDO_INIT, self.context.currentState.name)
        self.assertFalse(self.context.currentState.isContinuation)

        obj = TemporaryStateObject()
        obj[TASK_NAME_PARAM] = 'taskName'
        obj[RETRY_COUNT_PARAM] = 0

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-initial', self.context.currentState.name)
        self.assertEqual(0, _FantasmFanIn.all().count())

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-continuation', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-fan-in', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())

        event = self.context.dispatch(event, obj)
        self.assertEqual('state-final', self.context.currentState.name)
        self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 21
0
 def test_DatastoreFSMContinuationFanIn_smoke_test(self):
     event = self.context.initialize()
     self.assertTrue(FSM.PSEUDO_INIT, self.context.currentState.name)
     self.assertFalse(self.context.currentState.isContinuation)
     
     obj = TemporaryStateObject()
     obj[TASK_NAME_PARAM] = 'taskName'
     obj[RETRY_COUNT_PARAM] = 0
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-initial', self.context.currentState.name)
     self.assertEqual(0, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-continuation', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-fan-in', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
     
     event = self.context.dispatch(event, obj)
     self.assertEqual('state-final', self.context.currentState.name)
     self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 22
0
    def mergeJoinDispatch(self, event, obj):
        """ Performs a merge join on the pending fan-in dispatches.
        
        @param event: an event that is being merge joined (destination state must be a fan in) 
        @return: a list (possibly empty) of FSMContext instances
        """
        # this assertion comes from _queueDispatchFanIn - we never want fan-out info in a fan-in context
        assert not self.get(constants.GEN_PARAM)
        assert not self.get(constants.FORK_PARAM)
        
        # the work package index is stored in the url of the Task/FSMContext
        index = self.get(constants.INDEX_PARAM)
        taskNameBase = self.getTaskName(event, fanIn=True)
        
        # tell writers to use another index
        memcache.incr('index-' + taskNameBase)
        
        lock = '%s-lock-%d' % (taskNameBase, index)
        memcache.decr(lock, 2**15) # tell writers they missed the boat
        
        # 20 iterations * 0.25s = 5s total wait time
        busyWaitIters = 20
        busyWaitIterSecs = 0.250
        
        # busy wait for writers
        for i in xrange(busyWaitIters):
            counter = memcache.get(lock)
            # counter is None --> ejected from memcache
            # int(counter) <= 2**15 --> writers have all called memcache.decr
            if counter is None or int(counter) <= 2**15:
                break
            time.sleep(busyWaitIterSecs)
            self.logger.debug("Tried to acquire lock '%s' %d times...", lock, i + 1)
        
        # FIXME: is there anything else that can be done? will work packages be lost? maybe queue another task
        #        to sweep up later?
        if i >= (busyWaitIters - 1): # pylint: disable-msg=W0631
            self.logger.error("Gave up waiting for all fan-in work items.")
        
        # at this point we could have two tasks trying to process the same work packages. in the
        # happy path this will not likely happen because the tasks are sent off with different ETAs,
        # however in the unhappy path, it is possible for multiple tasks to be executing (retry on
        # 500 etc.). we solve this with a read lock using memcache.
        #
        # FIXME: would using a transaction on db.delete work if using ancestors? one task would win the
        #        race to delete the the work based on a transaction error?
        readlock = '%s-readlock-%d' % (taskNameBase, index)
        haveReadLock = False
        try:
            # put the actual name of the winning task into to lock
            actualTaskName = self.get(constants.TASK_NAME_PARAM)
            added = memcache.add(readlock, actualTaskName, time=30) # FIXME: is 30s appropriate?
            lockValue = memcache.get(readlock)
            
            # and return the FSMContexts list
            class FSMContextList(list):
                """ A list that supports .logger.info(), .logger.warning() etc.for fan-in actions """
                def __init__(self, context, contexts):
                    """ setup a self.logger for fan-in actions """
                    super(FSMContextList, self).__init__(contexts)
                    self.logger = Logger(context)
                    self.instanceName = context.instanceName
            
            # if the lock value is not equal to the added value, it means this task lost the race
            if not added or lockValue != actualTaskName:
                return FSMContextList(self, [])
#                raise FanInReadLockFailureRuntimeError(event, 
#                                                       self.machineName, 
#                                                       self.currentState.name, 
#                                                       self.instanceName)
            
            # flag used in finally block to decide whether or not to log an error message
            haveReadLock = True
                
            # fetch all the work packages in the current group for processing
            workIndex = '%s-%d' % (taskNameBase, knuthHash(index))
            query = _FantasmFanIn.all() \
                                 .filter('workIndex =', workIndex) \
                                 .order('__key__')
                                 
            # iterate over the query to fetch results - this is done in 'small batches'
            fanInResults = list(query)
            
            # construct a list of FSMContexts
            contexts = [self.clone(data=r.context) for r in fanInResults]

            # hold the fanInResult around in case we need to re-put them (on an Exception)
            obj[constants.FAN_IN_RESULTS_PARAM] = fanInResults
            
            # and delete the work packages - bearing in mind appengine limits
            maxDeleteSize = 250 # appengine does not like to delete > 500 models at a time, 250 is a nice safe number
            if len(fanInResults) > maxDeleteSize:
                self.logger.warning("%d contexts in the current batch. Consider decreasing fan-in.", len(fanInResults))
            i = 0
            while fanInResults[i:i+maxDeleteSize]:
                db.delete(fanInResults[i:i+maxDeleteSize])
                i += maxDeleteSize
                
            return FSMContextList(self, contexts)
        
        finally:
            deleted = memcache.delete(readlock)
            
            # FIXME: is there anything else that can be done? 
            if haveReadLock and deleted == memcache.DELETE_NETWORK_FAILURE:
                self.logger.error("Unable to release the fan in read lock.")
Esempio n. 23
0
 def post(self):
     """ Runs the serialized function """
     q = _FantasmFanIn.all().filter('workIndex =', self.request.POST['workIndex'])
     db.delete(q)
Esempio n. 24
0
 def test_mergeJoinDispatch_1_context(self):
     _FantasmFanIn(workIndex='instanceName--foo--event--foo2--step-0-2654435761').put()
     self.assertEqual(1, _FantasmFanIn.all().count())
     contexts = self.context.mergeJoinDispatch('event', {RETRY_COUNT_PARAM: 0})
     self.assertEqual([{'__ix__': 1, '__step__': 0}], contexts)
     self.assertEqual(1, _FantasmFanIn.all().count())
Esempio n. 25
0
 def post(self):
     """ Runs the serialized function """
     q = _FantasmFanIn.all().filter('workIndex =', self.request.POST[constants.WORK_INDEX_PARAM])
     db.delete(q)
Esempio n. 26
0
 def post(self):
     """ Runs the serialized function """
     q = _FantasmFanIn.all().filter(
         'workIndex =', self.request.POST[constants.WORK_INDEX_PARAM])
     db.delete(q)
Esempio n. 27
0
 def test_batchsize_3(self):
     self.context['batchsize'] = 3
     self.context.initialize() # queues the first task
     runQueuedTasks()
     self.assertEqual(4, _FantasmFanIn.all().count())
     self.assertEqual(self.EXPECTED_VALUES, sorted(ContinuationFanInResult.get_by_key_name('test').values))