Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions app/Jobs/PollForMediaWikiJobsJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Jobs;

use App\Services\MediaWikiHostResolver;
use App\Services\UnknownWikiDomainException;
use App\Wiki;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
Expand All @@ -25,11 +26,17 @@ public function handle(MediaWikiHostResolver $mwHostResolver): void {
}

private function hasPendingJobs(string $wikiDomain): bool {
$response = Http::withHeaders([
'host' => $wikiDomain,
])->get(
$this->mwHostResolver->getBackendUrlForDomain($wikiDomain) . '/w/api.php?action=query&meta=siteinfo&siprop=statistics&format=json'
);
try {
$response = Http::withHeaders([
'host' => $wikiDomain,
])->get(
$this->mwHostResolver->getBackendUrlForDomain($wikiDomain) . '/w/api.php?action=query&meta=siteinfo&siprop=statistics&format=json'
);
} catch (UnknownWikiDomainException $e) {
Log::warning('Skipping wiki ' . $wikiDomain . ' for pending MediaWiki jobs: ' . $e->getMessage());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this help us much? Are we just turning an error into a warning? Maybe this is still useful though.

I guess the question is what causes this to happen? Such a long runtime for this job that race conditions are common?

@dati18 dati18 Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question.

It does turn one failure mode from error to warning, but importantly it prevents a single stale domain from sabotaging the whole polling run.

To answer "Why this happens":

  1. The job reads a list of domains.
  2. Later, for each domain, resolver does another lookup.
  3. If a wiki is soft-deleted (or otherwise missing) between those moments, resolver throws UnknownWikiDomainException.

The root cause I think is "double-read on mutable data" under multiple updates. The longer the runtime, the longer the gap between 1 and 3, the higher the probability. So basically it's the gap between the time of "reading the data" vs "using the data"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! Sounds like we are getting closer to the root cause.

So could we refactor the job so we do this look up earlier? Or even in a single query?

I guess there might still be a case where the wiki really has now gone away

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, so you want to weed out bad domains instead of just "skipping" it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are correct that there is a double read. Actually there is a triple read:

  1. once to get the list of Wikis
  2. once to get the backendHost
  3. once when then MW backendHost determines the configuration of the Wiki

I am suggesting we merge the first two cases into one and get the correct backend hosts at the same time as we get the list of Wikis. There is still a chance that by the time we get to polling the Wikis that the 3rd read fails because it has been deleted but this is still a better solution.

Are you sure that marking the job as failed is sabotaging the whole run? I assumed that the job would still iterate over all Wikis but it would retry (sooner than planned) because it was marked as failed.


return false;
}

if ($response->failed()) {
$this->job->markAsFailed();
Expand Down
Loading