1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

Merge 9a0749c82b313d4abd31171beb7cca48bd56f19b into 104587314ff25a5c35390eeb42308f083e1e0488

This commit is contained in:
Adrian Vovk 2025-03-13 22:09:26 +01:00 committed by GitHub
commit 6927b071c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 75 additions and 23 deletions

View File

@ -8924,6 +8924,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t RandomizedDelayUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t RandomizedOffsetUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b FixedRandomDelay = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b Persistent = ...;
@ -8953,6 +8955,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<!--property RandomizedDelayUSec is not documented!-->
<!--property RandomizedOffsetUSec is not documented!-->
<!--property FixedRandomDelay is not documented!-->
<!--property Persistent is not documented!-->
@ -8997,6 +9001,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<variablelist class="dbus-property" generated="True" extra-ref="RandomizedDelayUSec"/>
<variablelist class="dbus-property" generated="True" extra-ref="RandomizedOffsetUSec"/>
<variablelist class="dbus-property" generated="True" extra-ref="FixedRandomDelay"/>
<variablelist class="dbus-property" generated="True" extra-ref="Persistent"/>

View File

@ -266,13 +266,13 @@
<listitem><para>Delay the timer by a randomly selected, evenly distributed amount of time between 0
and the specified time value. Defaults to 0, indicating that no randomized delay shall be applied.
Each timer unit will determine this delay randomly before each iteration, and the delay will simply
be added on top of the next determined elapsing time, unless modified with
<varname>FixedRandomDelay=</varname>, see below.</para>
Each timer unit will determine this delay randomly before each iteration, unless modified with
<varname>FixedRandomDelay=</varname>, see below. The delay is added on top of the next determined
elapsing time or the service manager's startup time, whichever is later.</para>
<para>This setting is useful to stretch dispatching of similarly configured timer events over a
certain time interval, to prevent them from firing all at the same time, possibly resulting in
resource congestion.</para>
resource congestion on the local system.</para>
<para>Note the relation to <varname>AccuracySec=</varname> above: the latter allows the service
manager to coalesce timer events within a specified time range in order to minimize wakeups, while
@ -292,12 +292,12 @@
<varlistentry>
<term><varname>FixedRandomDelay=</varname></term>
<listitem><para>Takes a boolean argument. When enabled, the randomized offset specified by
<varname>RandomizedDelaySec=</varname> is reused for all firings of the same timer. For a given timer
unit, the offset depends on the machine ID, user identifier and timer name, which means that it is
stable between restarts of the manager. This effectively creates a fixed offset for an individual
timer, reducing the jitter in firings of this timer, while still avoiding firing at the same time as
other similarly configured timers.</para>
<listitem><para>Takes a boolean argument. When enabled, the randomized delay specified by
<varname>RandomizedDelaySec=</varname> is chosen deterministically, and remains stable between all
firings of the same timer, even if the manager is restarted. The delay is derived from the machine
ID, the manager's user identifier, and the timer unit's name. This effectively creates a unique fixed
offset for each timer, reducing the jitter in firings of an individual timer while still avoiding
firing at the same time as other similarly configured timers.</para>
<para>This setting has no effect if <varname>RandomizedDelaySec=</varname> is set to 0. Defaults to
<option>false</option>.</para>
@ -305,6 +305,36 @@
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RandomizedOffsetSec=</varname></term>
<listitem><para>Offsets the timer by a stable, randomly-selected, and evenly distributed amount of
time between 0 and the specified time value. Defaults to 0, indicating that no such offset shall be
applied. The offset is chosen deterministically, and is derived the same way as
<varname>FixedRandomDelay=</varname>, see above. The offset is added on top of the next determined
elapsing time. This setting only has an effect on timers configured with <varname>OnCalendar=</varname>,
and it can be combined with <varname>RandomizedDelaySec=</varname>.</para>
<para>Much like <varname>RandomizedDelaySec=</varname>, this setting is for distributing timer events
to prevent them from firing all at once. However, this setting is most useful to prevent resource
congestion on a remote service, from a fleet of similarly-configured clients. Unlike
<varname>RandomizedDelaySec=</varname>, this setting applies its offset with no regard to manager
startup time. This maintains the periodicity of configured <varname>OnCalendar=</varname> events
across manager restarts.</para>
<para>For example, let's say you're running a backup service and have a fleet of laptops that wish
to make backups weekly. To distribute load on the backup service, each laptop should randomly pick
a weekday to upload its backups. This could be achieved by setting <varname>OnCalendar=</varname> to
<literal>weekly</literal>, and then configuring a <varname>RandomizedDelaySec=</varname> of
<literal>5 days</literal> with <varname>FixedRandomDelay=</varname> enabled. Let's say that some
laptop randomly chooses a delay of 4 days. If this laptop is restarted more often than that, then the
timer will never fire: on each fresh boot, the 4 day delay is restarted and will not be finished by
the time of the next shutdown. Instead, you should use <varname>RandomizedOffsetSec=</varname>, which
will maintain the configured weekly cadence of timer events, even across reboots.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DeferReactivation=</varname></term>

View File

@ -113,7 +113,8 @@ const sd_bus_vtable bus_timer_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_delay_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RandomizedOffsetUSec", "t", bus_property_get_usec, offsetof(Timer, random_offset_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FixedRandomDelay", "b", bus_property_get_bool, offsetof(Timer, fixed_random_delay), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
@ -214,7 +215,10 @@ static int bus_timer_set_transient_property(
}
if (streq(name, "RandomizedDelayUSec"))
return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
return bus_set_transient_usec(u, name, &t->random_delay_usec, message, flags, error);
if (streq(name, "RandomizedOffsetUSec"))
return bus_set_transient_usec(u, name, &t->random_offset_usec, message, flags, error);
if (streq(name, "FixedRandomDelay"))
return bus_set_transient_bool(u, name, &t->fixed_random_delay, message, flags, error);

View File

@ -578,7 +578,8 @@ Timer.RemainAfterElapse, config_parse_bool,
Timer.FixedRandomDelay, config_parse_bool, 0, offsetof(Timer, fixed_random_delay)
Timer.DeferReactivation, config_parse_bool, 0, offsetof(Timer, defer_reactivation)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec)
Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_delay_usec)
Timer.RandomizedOffsetSec, config_parse_sec, 0, offsetof(Timer, random_offset_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0
Path.PathExists, config_parse_path_spec, 0, 0
Path.PathExistsGlob, config_parse_path_spec, 0, 0

View File

@ -347,18 +347,18 @@ static void timer_enter_elapsed(Timer *t, bool leave_around) {
timer_enter_dead(t, TIMER_SUCCESS);
}
static void add_random(Timer *t, usec_t *v) {
static void add_random_delay(Timer *t, usec_t *v) {
usec_t add;
assert(t);
assert(v);
if (t->random_usec == 0)
if (t->random_delay_usec == 0)
return;
if (*v == USEC_INFINITY)
return;
add = (t->fixed_random_delay ? timer_get_fixed_delay_hash(t) : random_u64()) % t->random_usec;
add = (t->fixed_random_delay ? timer_get_fixed_delay_hash(t) : random_u64()) % t->random_delay_usec;
if (*v + add < *v) /* overflow */
*v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
@ -391,12 +391,19 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
continue;
if (v->base == TIMER_CALENDAR) {
usec_t b, rebased;
usec_t b, rebased, random_offset = 0;
if (t->random_offset_usec != 0)
random_offset = timer_get_fixed_delay_hash(t) % t->random_offset_usec;
/* If DeferReactivation= is enabled, schedule the job based on the last time
* the trigger unit entered inactivity. Otherwise, if we know the last time
* this was triggered, schedule the job based relative to that. If we don't,
* just start from the activation time or realtime. */
* just start from the activation time or realtime.
*
* Unless we have a real last-trigger time, we subtract the random_offset because
* any event that elapsed within the last random_offset has actually been delayed
* and thus hasn't truly elapsed yet. */
if (t->defer_reactivation &&
dual_timestamp_is_set(&trigger->inactive_enter_timestamp)) {
@ -408,14 +415,16 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
} else if (dual_timestamp_is_set(&t->last_trigger))
b = t->last_trigger.realtime;
else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
b = UNIT(t)->inactive_exit_timestamp.realtime;
b = UNIT(t)->inactive_exit_timestamp.realtime - random_offset;
else
b = ts.realtime;
b = ts.realtime - random_offset;
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)
continue;
v->next_elapse += random_offset;
/* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
* time has already passed, set the time when systemd first started as the scheduled
* time. Note that we base this on the monotonic timestamp of the boot, not the
@ -505,7 +514,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
if (found_monotonic) {
usec_t left;
add_random(t, &t->next_elapse_monotonic_or_boottime);
add_random_delay(t, &t->next_elapse_monotonic_or_boottime);
left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", FORMAT_TIMESPAN(left, 0));
@ -546,7 +555,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
}
if (found_realtime) {
add_random(t, &t->next_elapse_realtime);
add_random_delay(t, &t->next_elapse_realtime);
log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", FORMAT_TIMESTAMP(t->next_elapse_realtime));

View File

@ -41,7 +41,8 @@ struct Timer {
Unit meta;
usec_t accuracy_usec;
usec_t random_usec;
usec_t random_delay_usec;
usec_t random_offset_usec;
LIST_HEAD(TimerValue, values);
usec_t next_elapse_realtime;

View File

@ -2044,6 +2044,7 @@ org.freedesktop.systemd1.Timer.OnClockChange
org.freedesktop.systemd1.Timer.OnTimezoneChange
org.freedesktop.systemd1.Timer.Persistent
org.freedesktop.systemd1.Timer.RandomizedDelayUSec
org.freedesktop.systemd1.Timer.RandomizedOffsetUSec
org.freedesktop.systemd1.Timer.RemainAfterElapse
org.freedesktop.systemd1.Timer.Result
org.freedesktop.systemd1.Timer.TimersCalendar