commit ec6a7c0478c517f334d013969cd492d3d52e49e8
parent 0e86dfd5135d9ee706224be894915ab873a57a77
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Tue, 14 Jul 2026 23:37:54 +0200
limit donau /keys fetches
Diffstat:
1 file changed, 84 insertions(+), 3 deletions(-)
diff --git a/src/backend/taler-merchant-donaukeyupdate.c b/src/backend/taler-merchant-donaukeyupdate.c
@@ -169,6 +169,27 @@ struct ForceCharityCtx
* Handle to the charity update request.
*/
struct DONAU_CharityGetHandle *h;
+
+ /**
+ * Scheduler task for retrying a failed /charity_id request.
+ * This task will trigger the next attempt to download the charity
+ * details if the previous request could not be started.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * The delay before the next retry for fetching /charity_id.
+ * Used to implement exponential backoff in case of failures.
+ */
+ struct GNUNET_TIME_Relative retry_delay;
+
+ /**
+ * A flag indicating whether this charity inquiry is currently
+ * rate-limited. If true, the inquiry was postponed because we
+ * were at the #OPEN_INQUIRY_LIMIT and must be re-driven from
+ * end_inquiry() once a slot frees up.
+ */
+ bool limited;
};
/**
@@ -245,6 +266,15 @@ download_keys (void *cls);
/**
+ * Function that initiates a /charity_id download for a Donau instance.
+ *
+ * @param cls closure with a `struct ForceCharityCtx *`
+ */
+static void
+download_charity_id (void *cls);
+
+
+/**
* An inquiry finished, check if we need to start more.
*/
static void
@@ -269,6 +299,19 @@ end_inquiry (void)
if (at_limit)
break;
}
+ for (struct ForceCharityCtx *fcc = fcc_head;
+ NULL != fcc;
+ fcc = fcc->next)
+ {
+ if (at_limit)
+ break;
+ if (! fcc->limited)
+ continue;
+ fcc->limited = false;
+ /* done synchronously so that the active_inquiries
+ is updated immediately */
+ download_charity_id (fcc);
+ }
}
if ( (! at_limit) &&
(0 == active_inquiries) &&
@@ -621,13 +664,14 @@ donau_charity_cb (void *cls,
/**
* Download the charity_id for a Donau instance.
*
- * @param cls closure with a `struct Donau *`
+ * @param cls closure with a `struct ForceCharityCtx *`
*/
static void
download_charity_id (void *cls)
{
struct ForceCharityCtx *fcc = cls;
+ fcc->retry_task = NULL;
/* nothing to do if a request is already outstanding */
if (NULL != fcc->h)
return;
@@ -638,6 +682,10 @@ download_charity_id (void *cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Cannot start more charity inquiries, already at limit\n");
+ /* remember to re-drive this inquiry from end_inquiry()
+ once we are substantially below the limit again */
+ fcc->limited = true;
+ at_limit = true;
return;
}
@@ -655,6 +703,7 @@ download_charity_id (void *cls)
if (NULL != fcc->h)
{
+ fcc->retry_delay = GNUNET_TIME_UNIT_ZERO;
active_inquiries++;
}
else
@@ -662,8 +711,14 @@ download_charity_id (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to initiate DONAU_charity_get() for `%s'\n",
fcc->donau_url);
- /* we do NOT retry here – simply finish the (failed) inquiry */
- end_inquiry ();
+ /* no inquiry was started, so we must not call end_inquiry() here;
+ retry with exponential backoff instead */
+ fcc->retry_delay
+ = GNUNET_TIME_STD_BACKOFF (fcc->retry_delay);
+ fcc->retry_task
+ = GNUNET_SCHEDULER_add_delayed (fcc->retry_delay,
+ &download_charity_id,
+ fcc);
}
}
@@ -780,6 +835,12 @@ force_donau_charity_id (void *cls,
fcc->donau_url);
return;
}
+ if (NULL != fcc->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (fcc->retry_task);
+ fcc->retry_task = NULL;
+ }
+ fcc->charity_id = charity_id;
}
download_charity_id (fcc);
}
@@ -894,6 +955,26 @@ shutdown_task (void *cls)
d);
GNUNET_free (d);
}
+ while (NULL != fcc_head)
+ {
+ struct ForceCharityCtx *fcc = fcc_head;
+
+ if (NULL != fcc->h)
+ {
+ DONAU_charity_get_cancel (fcc->h);
+ fcc->h = NULL;
+ }
+ if (NULL != fcc->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (fcc->retry_task);
+ fcc->retry_task = NULL;
+ }
+ GNUNET_CONTAINER_DLL_remove (fcc_head,
+ fcc_tail,
+ fcc);
+ GNUNET_free (fcc->donau_url);
+ GNUNET_free (fcc);
+ }
if (NULL != eh)
{
TALER_MERCHANTDB_event_listen_cancel (eh);