-
Couldn't load subscription status.
- Fork 397
refactor: improve Worker public API and docs #1915
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
Conversation
workerextension.go
Outdated
|
|
||
| func (w *defaultWorker) ThreadActivatedNotification(_ int) { | ||
| func (w *defaultWorker) OnReady(_ int) { | ||
| w.activatedCount.Add(1) |
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.
What's the use case of this outside of tests @withinboredom? It looks unused
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.
It's called once a thread is ready to accept work. It makes more sense in the case of thread autoscaling, since you may need to handle threads going away and/or coming online.
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.
I mean the atomic int, not the method.
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.
oh, yeah. that's only used for tests 🤦
workerextension.go
Outdated
| InjectRequest(r *WorkerRequest) | ||
| // MinThreads returns the minimum number of threads to reserve from the FrankenPHP thread pool. | ||
| // This number must be positive. | ||
| MinThreads() int |
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.
Shouldn't we define a MaxThreads() method too, at least in the interface, to prevent a future BC break that we can prevent?
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.
These threads don't autoscale, so if someone returns 4 min threads and 8 max threads because it is on the interface, it won't do anything. Once we add autoscaling, then it makes more sense to have a MaxThreads(). Whether we want that change to be a breaking one or not, is a good question. :)
It might be a good idea to add it to the interface with one of two options (I'm partial to the second option):
- simply ignore max threads
- log a warning if they return different settings, something like:
extension "name" has configured different min/max threads but autoscaling is not implemented. min threads will be used.
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.
I'm a bit late to the review, but why expose the interface at all, won't it break on any change in the api?
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.
I'm not sure of what you mean. How could the extensions work if there is no public interface to implement?
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.
There would be less potential for breakage by just exposing a worker struct
type Worker struct {
onReady func()
onShutdown func()
....
}Even better would be sticking to how other library options are exposed.
worker := NewExternalWorker(
"fileName",
10,
injectRequest,
WithWorkerOnReady(..),
WithWorkerX(...),
)
workerextension.go
Outdated
|
|
||
| func (w *defaultWorker) ThreadActivatedNotification(_ int) { | ||
| func (w *defaultWorker) OnReady(_ int) { | ||
| w.activatedCount.Add(1) |
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.
It's called once a thread is ready to accept work. It makes more sense in the case of thread autoscaling, since you may need to handle threads going away and/or coming online.
workerextension.go
Outdated
| InjectRequest(r *WorkerRequest) | ||
| // MinThreads returns the minimum number of threads to reserve from the FrankenPHP thread pool. | ||
| // This number must be positive. | ||
| MinThreads() int |
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.
These threads don't autoscale, so if someone returns 4 min threads and 8 max threads because it is on the interface, it won't do anything. Once we add autoscaling, then it makes more sense to have a MaxThreads(). Whether we want that change to be a breaking one or not, is a good question. :)
It might be a good idea to add it to the interface with one of two options (I'm partial to the second option):
- simply ignore max threads
- log a warning if they return different settings, something like:
extension "name" has configured different min/max threads but autoscaling is not implemented. min threads will be used.
workerextension.go
Outdated
| // The returned request will be passed to the worker script. | ||
| GetRequest() *WorkerRequest | ||
| // SendRequest sends a request to the worker script. The callback function of frankenphp_handle_request() will be called. | ||
| SendRequest(r *WorkerRequest) |
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.
This method is not in use anywhere internally, why expose it in the interface?
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.
To allow things like this: https://github.com/dunglas/frankenphp-grpc/blob/main/grpc.go#L10
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.
Just confused about GetRequest and SendRequest. Wouldn't you always just want to send a message?
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.
IMO it would be much more elegant if there only was a SendRequest that just blocks until the message is finished. The user can call go SendRequest() if they want it to be non-blocking.
Needs less goroutines and allows writing more straightforward code. Instead of using AfterFunc for handling the return value, SendRequest can just return it directly or an error if something fails. AfterFunc feels like doing async-await in go 😅
workerextension.go
Outdated
|
|
||
| // EXPERIMENTAL | ||
| // EXPERIMENTAL: RegisterWorker registers a custom worker script. | ||
| func RegisterWorker(worker Worker) { |
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.
Aren't we essentially just registering a worker here? Wouldn't it make sense to just pass worker options like in WithWorkers?
WithWorkers(name string, fileName string, num int, options ...WorkerOption)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.
The worker can contain custom Go code like: https://github.com/dunglas/frankenphp-queue/blob/main/worker.go
We could maybe indeed pass a WithWokers option instead of having this global method, however. WDYT @withinboredom?
* Cleaner request apis.
First step for #1883 (comment)