Hi Augusto, We have considered using 3rd party graceful shutdown libraries; however, they mostly (all?) seem to re-implement the Server type. This means that if Go were to release a security fix, or other urgent fix to this logic, we wouldn't get it right away. We now depend on a 3rd party to keep up-to-date on something that is core-Go.
Since our requirements don't require a full "graceful" shutdown and are easily implemented in a few lines of code by wrapping the handler with an RLock, we would rather minimize the dependence on third party libraries. Thanks again, Evan On Tuesday, 13 September 2016 13:24:03 UTC-7, aro...@gmail.com wrote: > > The mutex approach is fundamentally broken because you can't guarantee > that the tasks are all started (and have a read-lock acquired) before you > call close. > > Consider: > h.Handle(...) <-- gets past the closed channel check, calls go ..., > butthe goroutine doesn't execute yet. > h.Close() <-- closes the close channel, Locks and Unlocks,returns. > ...now the goroutine executes and acquires the read lock. > > So really, if you can't control the Handle() function, you need two > WaitGroups: one to verify that all goroutines have started before shutting > down the task handler and a second one for all goroutines to have finished. > However, it's tricky if we don't know the real use case. > > Sounds like you are trying to do graceful http shutdown. Have you looked > at other libraries that do that? If you don't have a way to account for > the time between Handle(..) is called and the goroutine starts, you always > might miss a task that got called near the time Close() was called. > > - Augusto > > > On Tuesday, September 13, 2016 at 12:50:50 PM UTC-7, Evan Digby wrote: >> >> Hi Aroman, >> >> Your approach using the WaitGroup is definitely better in this toy >> example. The reason I didn't use the WaitGroup is because the non-toy >> example is wrapping the HTTP Server handler. I have no way to inject an >> "add" before the goroutine is created since that's handled by Go's HTTP >> Server without re-implementing the accept->handle loop using the listener. >> >> Apologies for not giving the full context in the example. >> >> I'm not sure how it could block an outstanding task since the closed >> channel is called before the Lock(), so no additional calls to RLock will >> be made at that point, and the Lock will just wait until all of the RLocks >> are complete. >> >> Regarding your testing strategy, I do like it better than any of my >> current strategy; however, There still is a chance that a task could >> complete between lines 90 and 91: >> >> h.Close() >> events <- ALL_TASKS_FINISHED >> >> So this doesn't solve the racy-ness I'm concerned about unless you put an >> arbitrary sleep in the handlers, which I'm trying to avoid. >> >> On Tuesday, 13 September 2016 12:34:17 UTC-7, aro...@gmail.com wrote: >>> >>> The WaitGroup is better than the lock approach, since the lock approach >>> could block an outstanding task. The key to using waitgroups is to call >>> Add() outside of goroutines that might call done: >>> >>> https://play.golang.org/p/QVWoy8fCmI >>> >>> On Tuesday, September 13, 2016 at 12:19:16 PM UTC-7, Evan Digby wrote: >>>> >>>> Hi John, >>>> >>>> Thanks for the reply. I've tried many incarnations that include >>>> WaitGroups; however, none seem to achieve the desired result. >>>> >>>> If I add a WaitGroup with a defer done in the handler, and then wait >>>> after the Close() then the test itself implements the requirement and >>>> won't >>>> protect from future refactors. There's no way to test that a WaitGroup is >>>> done without waiting for it, and even if there was it would be racy >>>> because >>>> between the Close() and WaitGroup wait call tasks could complete. If I >>>> wrapped the wait and the done in goroutines to see which one happened >>>> first, also racy. >>>> >>>> If you have something else in mind can you elaborate on how it would >>>> help in this case? >>>> >>>> Thanks again! >>>> >>>> Evan >>>> >>>> On Tuesday, 13 September 2016 12:01:29 UTC-7, John Souvestre wrote: >>>>> >>>>> Have you considered using a sync.WaitGroup? >>>>> >>>>> >>>>> >>>>> John >>>>> >>>>> John Souvestre - New Orleans LA >>>>> >>>>> >>>>> >>>>> *From:* golan...@googlegroups.com [mailto:golan...@googlegroups.com] *On >>>>> Behalf Of *Evan Digby >>>>> *Sent:* 2016 September 13, Tue 13:56 >>>>> *To:* golang-nuts >>>>> *Subject:* [go-nuts] Having difficulty testing this "cleanly" >>>>> >>>>> >>>>> >>>>> Has anyone come across a good way, non-racy way to ensure that N tasks >>>>> are guaranteed to be completed after a function is called? Essentially I >>>>> have a “Close” function that must be guaranteed to block until all tasks >>>>> are finished. Achieving this was pretty simple: wrap each task in an >>>>> RLock, >>>>> and then a Lock on close. >>>>> >>>>> >>>>> >>>>> Example: https://play.golang.org/p/7lhBPUhkUE >>>>> >>>>> >>>>> >>>>> Now I want to write a solid test to guarantee Close will meet that >>>>> requirement of all tasks must finish first for posterity. In that >>>>> example, >>>>> try commenting out the RLock/RUnlock on lines 25/26. You'll see that it >>>>> no >>>>> longer outputs many, if any, lines. I'm trying to prevent that from >>>>> happening in the future by some cowboy refactor! >>>>> >>>>> >>>>> >>>>> All of the ways I can come up with involve Sleeping or launching more >>>>> tasks than I _think_ can be finished in time--obviously not good! >>>>> >>>>> >>>>> >>>>> I feel like I must be missing some obvious way to test this and I'll >>>>> end up feeling silly once someone replies with the solution. I'm okay >>>>> with >>>>> that! >>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to golang-nuts...@googlegroups.com. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.