Skip to content

grpcsync: add ScheduleAndWait to CallbackSerializer#8998

Open
Retr0-XD wants to merge 8 commits intogrpc:masterfrom
Retr0-XD:feat/callbackserializer-schedule-and-wait-8501
Open

grpcsync: add ScheduleAndWait to CallbackSerializer#8998
Retr0-XD wants to merge 8 commits intogrpc:masterfrom
Retr0-XD:feat/callbackserializer-schedule-and-wait-8501

Conversation

@Retr0-XD
Copy link
Copy Markdown

@Retr0-XD Retr0-XD commented Mar 21, 2026

Description

Adds a ScheduleAndWait method to CallbackSerializer that schedules a callback and blocks until it has been executed.

This eliminates a repetitive pattern scattered throughout the codebase where callers create a done channel, close it inside the callback, and block on it:

// Before
done := make(chan struct{})
serializer.ScheduleOr(func(context.Context) {
    // Do stuff
    close(done)
}, func() {
    close(done)
})
<-done

// After
if err := serializer.ScheduleAndWait(func(ctx context.Context) {
    // Do stuff
}); err != nil {
    // handle ErrSerializerClosed
}

API

// ScheduleAndWait schedules the provided callback function f to be executed in
// the order it was added, and blocks until the callback has been executed. It
// returns nil once f has been run. If the context passed to
// NewCallbackSerializer was already canceled before this method is called, the
// callback will not be scheduled and ErrSerializerClosed is returned.
func (cs *CallbackSerializer) ScheduleAndWait(f func(ctx context.Context)) error

// ErrSerializerClosed is returned by ScheduleAndWait when the callback cannot
// be scheduled because the serializer has already been closed.
var ErrSerializerClosed = errors.New(\"grpcsync: serializer closed before the callback could be scheduled\")

Tests added

  • TestCallbackSerializer_ScheduleAndWait_Normal — happy path: callback executes and returns nil
  • TestCallbackSerializer_ScheduleAndWait_Closed — serializer already shut down: returns ErrSerializerClosed
  • TestCallbackSerializer_ScheduleAndWait_FIFO — FIFO ordering is preserved relative to TrySchedule
  • TestCallbackSerializer_ScheduleAndWait_Concurrent — 50 concurrent callers all complete successfully

RELEASE NOTES:

  • grpcsync: Add ScheduleAndWait method to CallbackSerializer for blocking callback execution

Fixes #8501


AI disclosure: GitHub Copilot was used during implementation and test writing. I fully understand all changes made in this PR.

Introduces ScheduleAndWait, which schedules a callback on the
CallbackSerializer and blocks until it has been executed. Returns nil
on success, or ErrSerializerClosed if the serializer was already shut
down at the time of the call.

This replaces a common pattern where callers create a done channel,
close it inside the scheduled callback, and then block on it.

Fixes grpc#8501
@Retr0-XD
Copy link
Copy Markdown
Author

Hi @dfawley @zasweq — would appreciate a review when you get a chance!

@easwars easwars requested a review from Pranjali-2501 March 24, 2026 03:41
@Retr0-XD
Copy link
Copy Markdown
Author

@Pranjali-2501 can you please review this PR :)

@Pranjali-2501
Copy link
Copy Markdown
Contributor

@Retr0-XD , CI is failing. Please fix it.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.00%. Comparing base (12e91dd) to head (f509f52).
⚠️ Report is 28 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8998      +/-   ##
==========================================
- Coverage   83.04%   83.00%   -0.05%     
==========================================
  Files         411      411              
  Lines       32892    32969      +77     
==========================================
+ Hits        27316    27365      +49     
- Misses       4181     4200      +19     
- Partials     1395     1404       +9     
Files with missing lines Coverage Δ
internal/grpcsync/callback_serializer.go 100.00% <100.00%> (ø)

... and 34 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Retr0-XD
Copy link
Copy Markdown
Author

Hi @Pranjali-2501 , CI fixed , the label is missing for PR validation check alone . Please review and let me know.

@Retr0-XD
Copy link
Copy Markdown
Author

Retr0-XD commented Apr 1, 2026

Let me know if anything else is required

@Pranjali-2501 Pranjali-2501 assigned arjan-bal and unassigned Retr0-XD Apr 1, 2026
@Pranjali-2501 Pranjali-2501 requested review from arjan-bal and removed request for Pranjali-2501 April 1, 2026 15:46
@arjan-bal arjan-bal removed their request for review April 7, 2026 03:56
@arjan-bal arjan-bal removed their assignment Apr 7, 2026
f(ctx)
close(done)
}) != nil {
return ErrSerializerClosed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of returning this new error sentinel given that this can fail only when the caller of this method cancels the context that they themselves passed to this method? Why not just return the error returned from Put as is.

@easwars easwars added the Type: Feature New features or improvements in behavior label Apr 8, 2026
@easwars easwars added this to the 1.81 Release milestone Apr 8, 2026
@easwars
Copy link
Copy Markdown
Contributor

easwars commented Apr 8, 2026

Also, can you please merge master into your branch. That should take care of the failing vet-proto CI.

Comment on lines +321 to +322
mu sync.Mutex
counter int
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Can we use an atomic.Int instead?


for i := 0; i < numCallbacks; i++ {
go func() {
defer wg.Done()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you consider using WaitGroup.Go. This is the new ergonomic way of spawning goroutines and waiting on them to complete with a WaitGroup.

See: https://pkg.go.dev/sync#WaitGroup.Go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: Requires Reporter Clarification Type: Feature New features or improvements in behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

callbackserializer: add a method to execute a callback in a blocking fashion

4 participants