-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rate-limiting: propagate back-pressure from queue as HTTP 429's #179
base: main
Are you sure you want to change the base?
Conversation
0413f83
to
0dbc4a7
Compare
0dbc4a7
to
1e85985
Compare
final boolean isCompact = execution.markComplete(); | ||
if (!isCompact) { | ||
this.compactTail(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review note:
The Execution#markComplete()
returns true iff marking the execution complete resulted in a node-level compaction. If it didn't, we try to compact from the tail.
if (preCompletionNext != null) { | ||
final Execution newNext = preCompletionNext.chaseTail(); | ||
return (newNext != preCompletionNext) && NEXT.compareAndSet(this, preCompletionNext, newNext); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review note:
We can't actually compact the completed node out, since we don't have a reference to its prev and a doubly-linked list is more complex than we need.
But we can fast-forward a newly-completed node's next
pointer to the first node in the sequence that is either not yet completed or has no next, which may be a compaction that frees up memory and reduces future computation.
When we succeed at compacting, we return true so that the caller can make decisions about performing additional compactions.
private static final java.lang.invoke.VarHandle NEXT; | ||
static { | ||
try { | ||
MethodHandles.Lookup l = MethodHandles.lookup(); | ||
NEXT = l.findVarHandle(Execution.class, "next", Execution.class); | ||
} catch (ReflectiveOperationException e) { | ||
throw new ExceptionInInitializerError(e); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, this is Java 9+, so we would need to guard against it being installed in Logstash 7 (or rework to use AtomicReference
s)
private final AtomicReference<Execution> head; // newest execution | ||
private final AtomicReference<Execution> tail; // oldest execution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: invert to match java semantics, where things go into the tail (back) of a queue and are removed from the head (front)
Adds a proactive handler that rejects new requests with HTTP 429's when the queue has been blocking for more than 10 consecutive seconds, allowing back- pressure to propagate in advance of filling up the connection backlog queue.
7200325
to
033f1d1
Compare
Adds a proactive handler that rejects new requests with HTTP 429's when the queue has been blocking for more than 10 consecutive seconds, allowing back- pressure to propagate in advance of filling up the connection backlog queue.
While I'd like to take the time to break out the supplied
ExecutionObserver
into a separate library, I think it is better to roll with what we have than to hold back.