Skip to content

Commit 5f73fb2

Browse files
authored
feat: Allow forcing of event method for requeued resource (#245)
* Add ability to specify event type when requeueing * Add setting to have requeue use the same callback as originally used
1 parent 06e28c6 commit 5f73fb2

File tree

4 files changed

+89
-12
lines changed

4 files changed

+89
-12
lines changed

src/KubeOps/Operator/Controller/ManagedResourceController{TEntity}.cs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal class ManagedResourceController<TEntity> : IManagedResourceController
3333
private readonly OperatorSettings _settings;
3434
private readonly IFinalizerManager<TEntity> _finalizerManager;
3535

36-
private readonly Subject<(TEntity Resource, TimeSpan Delay)>
36+
private readonly Subject<RequeuedEvent>
3737
_requeuedEvents = new();
3838

3939
private readonly Subject<QueuedEvent>
@@ -85,9 +85,17 @@ public ManagedResourceController(
8585
private IObservable<Unit> RequeuedEvents => _requeuedEvents
8686
.Do(_ => _metrics.RequeuedEvents.Inc())
8787
.Select(
88-
data => Observable.Return(data.Resource).Delay(data.Delay))
88+
data => Observable.Return(data).Delay(data.Delay))
8989
.Switch()
90-
.Select(data => Observable.FromAsync(() => UpdateResourceData(data)))
90+
.Select(data =>
91+
Observable.FromAsync(async () =>
92+
{
93+
var queuedEvent = await UpdateResourceData(data.Resource);
94+
95+
return data.ResourceEvent.HasValue && queuedEvent != null
96+
? queuedEvent with { ResourceEvent = data.ResourceEvent.Value }
97+
: queuedEvent;
98+
}))
9199
.Switch()
92100
.Where(data => data != null)
93101
.Do(
@@ -269,13 +277,32 @@ protected async Task HandleResourceEvent(QueuedEvent? data)
269277
resource.Name());
270278
return;
271279
case RequeueEventResult requeue:
272-
_logger.LogInformation(
273-
@"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue requested with delay ""{requeue}"".",
274-
@event,
275-
resource.Kind,
276-
resource.Name(),
277-
requeue.RequeueIn);
278-
_requeuedEvents.OnNext((resource, requeue.RequeueIn));
280+
if (_settings.DefaultRequeueAsSameType)
281+
{
282+
requeue = new RequeueEventResult(requeue.RequeueIn, @event);
283+
}
284+
285+
if (requeue.EventType.HasValue)
286+
{
287+
_logger.LogInformation(
288+
@"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue requested as type ""{requeueType}"" with delay ""{requeue}"".",
289+
@event,
290+
resource.Kind,
291+
resource.Name(),
292+
requeue.EventType,
293+
requeue.RequeueIn);
294+
}
295+
else
296+
{
297+
_logger.LogInformation(
298+
@"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue requested with delay ""{requeue}"".",
299+
@event,
300+
resource.Kind,
301+
resource.Name(),
302+
requeue.RequeueIn);
303+
}
304+
305+
_requeuedEvents.OnNext(new RequeuedEvent(requeue.EventType, resource, requeue.RequeueIn));
279306
break;
280307
}
281308
}
@@ -417,5 +444,7 @@ private TimeSpan ExponentialBackoff(int retryCount) => TimeSpan
417444
.Add(TimeSpan.FromMilliseconds(_rnd.Next(0, 1000)));
418445

419446
internal record QueuedEvent(ResourceEventType ResourceEvent, TEntity Resource, int RetryCount = 0);
447+
448+
private record RequeuedEvent(ResourceEventType? ResourceEvent, TEntity Resource, TimeSpan Delay);
420449
}
421450
}

src/KubeOps/Operator/Controller/Results/RequeueEventResult.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using KubeOps.Operator.Kubernetes;
23

34
namespace KubeOps.Operator.Controller.Results
45
{
@@ -8,5 +9,10 @@ public RequeueEventResult(TimeSpan requeueIn)
89
: base(requeueIn)
910
{
1011
}
12+
13+
public RequeueEventResult(TimeSpan requeueIn, ResourceEventType eventType)
14+
: base(requeueIn, eventType)
15+
{
16+
}
1117
}
1218
}

src/KubeOps/Operator/Controller/Results/ResourceControllerResult.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using KubeOps.Operator.Events;
23
using KubeOps.Operator.Kubernetes;
34

45
namespace KubeOps.Operator.Controller.Results
@@ -10,13 +11,27 @@ namespace KubeOps.Operator.Controller.Results
1011
/// </summary>
1112
public abstract class ResourceControllerResult
1213
{
13-
internal ResourceControllerResult(TimeSpan delay) => RequeueIn = delay;
14+
internal ResourceControllerResult(TimeSpan delay)
15+
{
16+
RequeueIn = delay;
17+
}
18+
19+
internal ResourceControllerResult(TimeSpan delay, ResourceEventType eventType)
20+
{
21+
RequeueIn = delay;
22+
EventType = eventType;
23+
}
1424

1525
/// <summary>
1626
/// Time that should be waited for a requeue.
1727
/// </summary>
1828
public TimeSpan RequeueIn { get; }
1929

30+
/// <summary>
31+
/// Type of the event to be queued.
32+
/// </summary>
33+
public ResourceEventType? EventType { get; }
34+
2035
/// <summary>
2136
/// Create a <see cref="ResourceControllerResult"/> that requeues a resource
2237
/// with a given delay. When the event fires (after the delay) the resource
@@ -31,6 +46,21 @@ public abstract class ResourceControllerResult
3146
public static ResourceControllerResult RequeueEvent(TimeSpan delay)
3247
=> new RequeueEventResult(delay);
3348

34-
// TODO: Requeue with forced event method
49+
/// <summary>
50+
/// Create a <see cref="ResourceControllerResult"/> that requeues a resource
51+
/// with a given delay. When the event fires (after the delay) the resource
52+
/// cache is ignored in favor the specified <see cref="ResourceEventType"/>.
53+
/// Based on the specified type, the new event triggers the according function.
54+
/// </summary>
55+
/// <param name="delay">
56+
/// The delay. Please note, that a delay of <see cref="TimeSpan.Zero"/>
57+
/// will result in an immediate trigger of the function. This can lead to infinite circles.
58+
/// </param>
59+
/// <param name="eventType">
60+
/// The event type to queue.
61+
/// </param>
62+
/// <returns>The <see cref="ResourceControllerResult"/> with the configured delay and event type.</returns>
63+
public static ResourceControllerResult RequeueEvent(TimeSpan delay, ResourceEventType eventType)
64+
=> new RequeueEventResult(delay, eventType);
3565
}
3666
}

src/KubeOps/Operator/OperatorSettings.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,17 @@ public sealed class OperatorSettings
7878
/// <para>The search will be performed on each "Start" of the controller.</para>
7979
/// </summary>
8080
public bool PreloadCache { get; set; }
81+
82+
/// <summary>
83+
/// <para>
84+
/// If set to true, returning `ResourceControllerResult.RequeueEvent` will
85+
/// automatically requeue the event as the same type.
86+
/// </para>
87+
/// <para>
88+
/// For example, if done from a "Created" event, the event will be queued
89+
/// again as "Created" instead of (for example) "NotModified".
90+
/// </para>
91+
/// </summary>
92+
public bool DefaultRequeueAsSameType { get; set; } = false;
8193
}
8294
}

0 commit comments

Comments
 (0)