Skip to content
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

Make more client services into startstop.Service #262

Merged
merged 1 commit into from
Mar 12, 2024

Conversation

brandur
Copy link
Contributor

@brandur brandur commented Mar 10, 2024

Here, we aim to move in a direction where the client can treat most of
its subservices generically by starting/stopping the notifier as a
generic service, along with converting three other smaller services over
to use the startstop.Service interface:

  • Client monitor. (This ends up cleaning up its internal code
    significantly, and has a major improvement on its test coverage and
    robustness.)

  • The client's statistics logging loop.

  • The client's leadership change handling loop.

Both the latter two are very small functions, so I implement the new
function startstop.StartStopFunc which similar to river.WorkFunc,
provides an easy way to get a small service using only a function, which
keeps the code quite clean.

It's going to take a few more changes to get our full simplification
change, but you can already see the beginnings of it as many services
can be started and stopped in ~one line:

func (c *Client[TTx]) signalStopComplete(ctx context.Context) {
    // Wait for producers and elector to exit:
    c.wg.Wait()

    // Stop all mainline services where stop order isn't important.
    startstop.StopAllParallel(c.services)

By the end of it, both the elector and producers will also become
services, and we'll be able to fully eliminate the wait group, along
with the stop channels and the roundabout stop functions like
signalStopComplete. The idea is that the client itself will also
become a start/stop service, and itself become protected against being
started multiple times, or potential races where Start/Stop may be
called by multiple goroutines.

//
// Unlike other services, it's given a background context so that it doesn't
// cancel on normal stops.
if err := c.monitor.Start(context.Background()); err != nil { //nolint:contextcheck
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Won't return an error, but like other services, it has the option to do so.

// In case of error, stop any services that might have started. This
// is safe because even services that were never started will still
// tolerate being stopped.
startstop.StopAllParallel(c.services)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We now try and stop anything that started even in the event of a start error, which is kind of nice.

Here, we aim to move in a direction where the client can treat most of
its subservices generically by starting/stopping the notifier as a
generic service, along with converting three other smaller services over
to use the `startstop.Service` interface:

* Client monitor. (This ends up cleaning up its internal code
  significantly, and has a major improvement on its test coverage and
  robustness.)

* The client's statistics logging loop.

* The client's leadership change handling loop.

Both the latter two are very small functions, so I implement the new
function `startstop.StartStopFunc` which similar to `river.WorkFunc`,
provides an easy way to get a small service using only a function, which
keeps the code quite clean.

It's going to take a few more changes to get our full simplification
change, but you can already see the beginnings of it as many services
can be started and stopped in ~one line:

    func (c *Client[TTx]) signalStopComplete(ctx context.Context) {
        // Wait for producers and elector to exit:
        c.wg.Wait()

        // Stop all mainline services where stop order isn't important.
        startstop.StopAllParallel(c.services)

By the end of it, both the elector and producers will also become
services, and we'll be able to fully eliminate the wait group, along
with the stop channels and the roundabout stop functions like
`signalStopComplete`. The idea is that the client itself will also
become a start/stop service, and itself become protected against being
started multiple times, or potential races where `Start`/`Stop` may be
called by multiple goroutines.
}
}
}()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This all just moves down from above where it was previously in a closure.


shutdownOnce: &sync.Once{},
shutdownCh: make(chan struct{}),
doneCh: make(chan struct{}),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lets us get rid of a whole bunch of vars, which is nice. We add a StartStopStress test case also, so we're now much more certain that this code works than before.

@brandur brandur force-pushed the brandur-client-services branch from b1a01f5 to 69ef596 Compare March 10, 2024 19:21
@brandur brandur requested a review from bgentry March 10, 2024 19:27
@brandur
Copy link
Contributor Author

brandur commented Mar 10, 2024

@bgentry I'm sure you're just going to love this one lol, but I promise it's for the greater good.

brandur added a commit that referenced this pull request Mar 11, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 11, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 11, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
@bgentry
Copy link
Contributor

bgentry commented Mar 11, 2024

@bgentry I'm sure you're just going to love this one lol, but I promise it's for the greater good.

Actually wasn't too bad at all :)

@brandur
Copy link
Contributor Author

brandur commented Mar 12, 2024

Actually wasn't too bad at all :)

Hah, okay that's a relief :) Thanks!

@brandur brandur merged commit ccea9c7 into master Mar 12, 2024
10 checks passed
@brandur brandur deleted the brandur-client-services branch March 12, 2024 00:24
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
brandur added a commit that referenced this pull request Mar 12, 2024
)

Follow up changes like #253, #262, and #263 to make the producer a
start/stop service, giving it a more predictable way to invoke start and
stop, making it safer to run and cleaning up caller code where it's used
in the client and test cases. With all these changes taken together
we'll have every service in the client using the same unified service
interface, which will clean up code and let us write some neat utilities
to operate across all of them.

Aside from that, we clean up the producer in ways to bring it more
inline with other code, like making logging uniform and having the
constructor return only a `*producer` instead of `(*producer, error)`
that needs to be checked despite an error always being indicative of a
bug in this context.

We expand the test suite, adding tests like (1) verifying that workers
are really stopped when `workCtx` is cancelled, (2) verifying that the
max worker slots work as expected and that the producer limits its
fetches, and (3) start/stop stress.

Like with #263, we give the producer a poll only mode, which also gets
the full test barrage using a shared test transaction instead of full
database pool. Also like #263, this poll only mode is still prospective
and not yet put to full use (although it will be soon).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants