strvcom / strv-backend-go-background

Never lose your goroutine again.

Home Page:https://go.strv.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The road to `v0.1` 🚀

robertrossmann opened this issue · comments

Use this issue to leave feedback as to what you think needs to be done before publishing our very first v0.1 release of go.strv.io/background package.

The release is planned for Monday, 18th of March but it might be postponed if needed, based on the received feedback.

The manager does not respect cancelation of the context. Is this intentional behavior? I would expect that when the context passed to the RunTask is cancelled, the manager cancels the task.

I would add a constructor for the Slog observer and for the Default observer as well.

Note regarding the documentation: often times the word schedule is used, but my understanding is that there's no scheduling happening, just execution. Did I get that wrong? If not, I would propose rewording.

The manager is prone to race condition:

Example is calling the following consecutive calls:

	manager.Close()
	manager.RunTask(ctx, def)

Also, I guess I shouldn't be able to call Close twice, neither should I be able to run tasks after closing the manager?

I would remove Multi observer. It's a piece of code that does not bring any value to the codebase and adds to the cognitive complexity of the codebase unnecessarily.

internal.go in the root feels weird, I would consider putting it at least under the internal/ folder.

How do I stop the task if the task is stalled? I can imagine that one of the use cases for the OnTaskStalled callback could be either to restart the task or to kill it.

@CermakM thank you for taking the time to look at the codebase and provide feedback. ❤️ Below you will find my responses to your review notes.

The manager does not respect cancelation of the context. Is this intentional behavior?

Very much intentional. Usually you run a background task from the context of a request, and you definitely want the background task to continue running even when the request has been processed and response delivered.

The manager is prone to race condition

Not sure where exactly the race condition happens here, please explain. 🙏 Generally, if you schedule one-off tasks after calling .Close() the task will run as usual and .Close() will wait for it. Scheduling a looping task while and after .Close()ing is a no-op.

I guess I shouldn't be able to call Close twice

I actually think you should be able to do that and the result should always be the same. However, it is somewhat pointless as usually you want to call .Close() from the main thread so consecutive calls would yield no further results. Generally, though, I'd prefer to have the API made in such a way that it does not matter how many times you call it, the result should be still the same.

I guess you could end up in a weird situation where you call .Close(), that call returns (all tasks complete) and you schedule new one-off tasks. Not really sure what would be the correct behaviour here, for now I think we can add a note to the documentation that one should take care to not schedule more work after calling .Close(). We can figure out something better in future iterations. 💪

I would add a constructor for the Slog observer and for the Default observer as well.

I thought about this as well, I went ctor-less way because there was nothing needed to be done in them. Perhaps I can add them to future-proof the API. 🤔

internal.go in the root feels weird

If I move it to internal/ folder then it becomes a package, even if internal still. The functions therein are implementation details of the background package; the functionality in internal.go is not really re-usable in other places. Perhaps a different name for the file would fit better? I could also move the functions back to background.go. 🤷‍♂️

How do I stop the task if the task is stalled?

You cannot at the moment. The only way out is to let the task run to completion - the OnTaskStalled hook is really only meant for alerting of potentially suspicious behaviour. We can think of one-off task cancellation in a future iteration, it is something that I thought about adding as well but wanted to first give the package a good production spin to see if that would really be useful.

  • I would remove Multi observer. - will remove. 👍
  • often times the word schedule is used - I'll update the docs. 👍

Thanks for the answers! I'll move some of the points to their respective issues to make the conversation easier, if you don't mind.

internal.go in the root feels weird

True that, fair. I would move it to the background.go then 👍

Created #17 and #16 to discuss the race and the cancellation 👍

Also, regarding future proofing, I would also add task.New constructor for the Task. In general, ctor functions in Go are more than just a sugar code, it's also a way to denote the required arguments. For example, the task.Task can not run without the Fn, but can run without Retry. There can be more fields in the future and it becomes overwhelming to navigate what is required and what is not. A constructor function with Options pattern is quite a handy and straightforward way to denote that.

Also a nitpick here (but I believe useful in general). It's a good practice to define the errors where they are being used. For example here:

ErrUnknownType = errors.New("unknown task type")

This error is defined in the task package but is used in the background package and nowhere else. Since RunTask validates the type of the task it can execute, I believe the background package should define that error.

I would also rename s/samples/examples -> examples is quite a standard and also semantically better I would say.

I would just add here, that v0.1 is already released, so I would close this issue and create new milestone v0.2, where new issues can be addresed.