mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 10:31:50 +01:00
fix: Add retry logic for ad publishing (3 attempts before skipping) (#774)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-FileCopyrightText: © Sebastian Thomschke and contributors
|
# SPDX-FileCopyrightText: © Sebastian Thomschke and contributors
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
||||||
import atexit, enum, json, os, re, signal, sys, textwrap # isort: skip
|
import atexit, asyncio, enum, json, os, re, signal, sys, textwrap # isort: skip
|
||||||
import getopt # pylint: disable=deprecated-module
|
import getopt # pylint: disable=deprecated-module
|
||||||
import urllib.parse as urllib_parse
|
import urllib.parse as urllib_parse
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -10,6 +10,7 @@ from pathlib import Path
|
|||||||
from typing import Any, Final
|
from typing import Any, Final
|
||||||
|
|
||||||
import certifi, colorama, nodriver # isort: skip
|
import certifi, colorama, nodriver # isort: skip
|
||||||
|
from nodriver.core.connection import ProtocolException
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from wcmatch import glob
|
from wcmatch import glob
|
||||||
|
|
||||||
@@ -1021,6 +1022,8 @@ class KleinanzeigenBot(WebScrapingMixin):
|
|||||||
|
|
||||||
async def publish_ads(self, ad_cfgs:list[tuple[str, Ad, dict[str, Any]]]) -> None:
|
async def publish_ads(self, ad_cfgs:list[tuple[str, Ad, dict[str, Any]]]) -> None:
|
||||||
count = 0
|
count = 0
|
||||||
|
failed_count = 0
|
||||||
|
max_retries = 3
|
||||||
|
|
||||||
published_ads = json.loads(
|
published_ads = json.loads(
|
||||||
(await self.web_request(f"{self.root_url}/m-meine-anzeigen-verwalten.json?sort=DEFAULT"))["content"])["ads"]
|
(await self.web_request(f"{self.root_url}/m-meine-anzeigen-verwalten.json?sort=DEFAULT"))["content"])["ads"]
|
||||||
@@ -1033,16 +1036,40 @@ class KleinanzeigenBot(WebScrapingMixin):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
success = False
|
||||||
|
|
||||||
|
# Retry loop only for publish_ad (before submission completes)
|
||||||
|
for attempt in range(1, max_retries + 1):
|
||||||
|
try:
|
||||||
await self.publish_ad(ad_file, ad_cfg, ad_cfg_orig, published_ads, AdUpdateStrategy.REPLACE)
|
await self.publish_ad(ad_file, ad_cfg, ad_cfg_orig, published_ads, AdUpdateStrategy.REPLACE)
|
||||||
|
success = True
|
||||||
|
break # Publish succeeded, exit retry loop
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
raise # Respect task cancellation
|
||||||
|
except (TimeoutError, ProtocolException) as ex:
|
||||||
|
if attempt < max_retries:
|
||||||
|
LOG.warning(_("Attempt %s/%s failed for '%s': %s. Retrying..."), attempt, max_retries, ad_cfg.title, ex)
|
||||||
|
await self.web_sleep(2) # Wait before retry
|
||||||
|
else:
|
||||||
|
LOG.error(_("All %s attempts failed for '%s': %s. Skipping ad."), max_retries, ad_cfg.title, ex)
|
||||||
|
failed_count += 1
|
||||||
|
|
||||||
|
# Check publishing result separately (no retry - ad is already submitted)
|
||||||
|
if success:
|
||||||
|
try:
|
||||||
publish_timeout = self._timeout("publishing_result")
|
publish_timeout = self._timeout("publishing_result")
|
||||||
await self.web_await(self.__check_publishing_result, timeout = publish_timeout)
|
await self.web_await(self.__check_publishing_result, timeout = publish_timeout)
|
||||||
|
except TimeoutError:
|
||||||
|
LOG.warning(_(" -> Could not confirm publishing for '%s', but ad may be online"), ad_cfg.title)
|
||||||
|
|
||||||
if self.config.publishing.delete_old_ads == "AFTER_PUBLISH" and not self.keep_old_ads:
|
if success and self.config.publishing.delete_old_ads == "AFTER_PUBLISH" and not self.keep_old_ads:
|
||||||
await self.delete_ad(ad_cfg, published_ads, delete_old_ads_by_title = False)
|
await self.delete_ad(ad_cfg, published_ads, delete_old_ads_by_title = False)
|
||||||
|
|
||||||
LOG.info("############################################")
|
LOG.info("############################################")
|
||||||
LOG.info("DONE: (Re-)published %s", pluralize("ad", count))
|
if failed_count > 0:
|
||||||
|
LOG.info(_("DONE: (Re-)published %s (%s failed after retries)"), pluralize("ad", count - failed_count), failed_count)
|
||||||
|
else:
|
||||||
|
LOG.info(_("DONE: (Re-)published %s"), pluralize("ad", count))
|
||||||
LOG.info("############################################")
|
LOG.info("############################################")
|
||||||
|
|
||||||
async def publish_ad(self, ad_file:str, ad_cfg:Ad, ad_cfg_orig:dict[str, Any], published_ads:list[dict[str, Any]],
|
async def publish_ad(self, ad_file:str, ad_cfg:Ad, ad_cfg_orig:dict[str, Any], published_ads:list[dict[str, Any]],
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ kleinanzeigen_bot/__init__.py:
|
|||||||
publish_ads:
|
publish_ads:
|
||||||
"Processing %s/%s: '%s' from [%s]...": "Verarbeite %s/%s: '%s' von [%s]..."
|
"Processing %s/%s: '%s' from [%s]...": "Verarbeite %s/%s: '%s' von [%s]..."
|
||||||
"Skipping because ad is reserved": "Überspringen, da Anzeige reserviert ist"
|
"Skipping because ad is reserved": "Überspringen, da Anzeige reserviert ist"
|
||||||
|
" -> Could not confirm publishing for '%s', but ad may be online": " -> Veröffentlichung für '%s' konnte nicht bestätigt werden, aber Anzeige ist möglicherweise online"
|
||||||
|
"Attempt %s/%s failed for '%s': %s. Retrying...": "Versuch %s/%s fehlgeschlagen für '%s': %s. Erneuter Versuch..."
|
||||||
|
"All %s attempts failed for '%s': %s. Skipping ad.": "Alle %s Versuche fehlgeschlagen für '%s': %s. Überspringe Anzeige."
|
||||||
|
"DONE: (Re-)published %s (%s failed after retries)": "FERTIG: %s (erneut) veröffentlicht (%s fehlgeschlagen nach Wiederholungen)"
|
||||||
"DONE: (Re-)published %s": "FERTIG: %s (erneut) veröffentlicht"
|
"DONE: (Re-)published %s": "FERTIG: %s (erneut) veröffentlicht"
|
||||||
"ad": "Anzeige"
|
"ad": "Anzeige"
|
||||||
apply_auto_price_reduction:
|
apply_auto_price_reduction:
|
||||||
|
|||||||
Reference in New Issue
Block a user