def _ensure_complete(self): if not (self._is_data_complete() and self._is_background_github_processing_completed()): self.pull = self.client.item(f"pulls/{self.pull['number']}") if not self._is_data_complete(): self.log.error( "/pulls/%s has returned an incomplete payload...", self.pull["number"], data=self.pull, ) if self._is_background_github_processing_completed(): return raise exceptions.MergeableStateUnknown(self)
def _ensure_mergable_state(self, force=False): if self.g_pull.state == "closed": return if not force and self.g_pull.mergeable_state not in self.UNUSABLE_STATES: return # Github is currently processing this PR, we wait the completion LOG.info("refreshing", pull_request=self) # NOTE(sileht): Well github doesn't always update etag/last_modified # when mergeable_state change, so we get a fresh pull request instead # of using update() self.g_pull = self.g_pull.base.repo.get_pull(self.g_pull.number) if (self.g_pull.state == "closed" or self.g_pull.mergeable_state not in self.UNUSABLE_STATES): return raise exceptions.MergeableStateUnknown(self)
async def test_stream_processor_retrying_pull(run_engine, _, logger_class, redis_stream, redis_cache): logs.setup_logging() logger = logger_class.return_value # One retries once, the other reaches max_retry run_engine.side_effect = [ exceptions.MergeableStateUnknown(mock.Mock()), exceptions.MergeableStateUnknown(mock.Mock()), mock.Mock(), exceptions.MergeableStateUnknown(mock.Mock()), exceptions.MergeableStateUnknown(mock.Mock()), ] await worker.push( redis_stream, 123, "owner", "repo", 123, "pull_request", {"payload": "whatever"}, ) await worker.push( redis_stream, 123, "owner", "repo", 42, "comment", {"payload": "foobar"}, ) assert 1 == (await redis_stream.zcard("streams")) assert 1 == len(await redis_stream.keys("stream~*")) assert 2 == await redis_stream.xlen("stream~owner~123") assert 0 == len(await redis_stream.hgetall("attempts")) p = worker.StreamProcessor(redis_stream, redis_cache) await p.consume("stream~owner~123") assert len(run_engine.mock_calls) == 2 assert run_engine.mock_calls == [ mock.call( InstallationMatcher(owner="owner"), "repo", 123, [ { "event_type": "pull_request", "data": { "payload": "whatever" }, "timestamp": mock.ANY, }, ], ), mock.call( InstallationMatcher(owner="owner"), "repo", 42, [ { "event_type": "comment", "data": { "payload": "foobar" }, "timestamp": mock.ANY, }, ], ), ] # Check stream still there and attempts recorded assert 1 == (await redis_stream.zcard("streams")) assert 1 == len(await redis_stream.keys("stream~*")) assert { b"pull~owner~repo~42": b"1", b"pull~owner~repo~123": b"1", } == await redis_stream.hgetall("attempts") await p.consume("stream~owner~123") assert 1 == (await redis_stream.zcard("streams")) assert 1 == len(await redis_stream.keys("stream~*")) assert 1 == len(await redis_stream.hgetall("attempts")) assert len(run_engine.mock_calls) == 4 assert { b"pull~owner~repo~42": b"2" } == await redis_stream.hgetall("attempts") await p.consume("stream~owner~123") assert len(run_engine.mock_calls) == 5 # Too many retries, everything is gone assert 3 == len(logger.info.mock_calls) assert 1 == len(logger.error.mock_calls) assert logger.info.mock_calls[0].args == ( "failed to process pull request, retrying", ) assert logger.info.mock_calls[1].args == ( "failed to process pull request, retrying", ) assert logger.error.mock_calls[0].args == ( "failed to process pull request, abandoning", ) assert 0 == (await redis_stream.zcard("streams")) assert 0 == len(await redis_stream.keys("stream~*")) assert 0 == len(await redis_stream.hgetall("attempts"))