def test_prepare(self): prepare = Prepare(id=3, key='biz', predicate='set', argument='a') self.assertEqual(prepare.to_json(), { 'id': 3, 'key': 'biz', 'predicate': 'set', 'argument': 'a' }) target = Prepare._id prepare = Prepare(key='buzz', predicate='a', argument='b') self.assertEqual(prepare.to_json(), { 'id': target, 'key': 'buzz', 'predicate': 'a', 'argument': 'b' }) _ = yield self.assert_send_works(prepare, '/prepare') request = tornado.httpclient.HTTPRequest( body=json.dumps(prepare.to_json()), method='POST', headers={'Content-Type': 'application/json'}, url='/prepare') target = Prepare.from_request(request) self.assertEqual(target.to_json(), prepare.to_json())
def post(self): prepare = Prepare.from_request(self.request) in_progress = Promises.current.get(prepare.key) last_accepted = Learner.completed_rounds.highest_numbered(prepare.key) if in_progress: logger.info("Promise in progress already %s", in_progress) if in_progress.prepare.id == prepare.id: raise Exception("Prepare IDs match.") if in_progress.prepare.id > prepare.id: # Some replica has issued a higher promise # than ours. Abort. logger.warning("Existing promise is higher.") self.respond(code=400, message=in_progress) elif last_accepted is None or ( in_progress.prepare.id > last_accepted.prepare.id ): # >= since we could have just learned but not removed the existing process because this is all async # Complete the in-progress promise first # Possible for the incoming promise to have the same ID as the existing one. logger.info("Must complete earlier promise first: %s", in_progress) self.respond(code=200, message=in_progress) else: logger.info("New promise is higher. Issuing promise.") self.respond(code=200, message=Promise()) elif last_accepted is None or prepare.id > last_accepted.prepare.id: logger.info("Adding a new promise for prepare %s", prepare) Promises.current.add(Promise(prepare=prepare)) self.respond(code=200, message=Promise()) else: logger.warning( "Prepare has a lower ID than the last accepted proposal") logger.warning("prepare: %s, last_accepted: %s", prepare, last_accepted) self.respond(code=400, message=last_accepted)