Service structs
Encore lets you define a type, called a service struct, to represent your running service. This lets you define an initialization function (similar to the main
function in regular Go programs).
You can also define API endpoints as methods on the service struct type, enabling you to use dependency injection for testing purposes.
It works by defining a struct type of your choice (typically called Service
)
and declaring it with //encore:service
.
Then, you can define a special function named initService
(or initWhatever
if you named the type Whatever
)
that gets called by Encore to initialize your service when it starts up.
It looks like this:
//encore:service
type Service struct {
// Add your dependencies here
}
func initService() (*Service, error) {
// Write your service initialization code here.
}
//encore:api public
func (s *Service) MyAPI(ctx context.Context) error {
// ...
}
Related example
$ encore app create --example=uptime
Calling APIs defined on service structs
When using a service struct like above, Encore will create a file named encore.gen.go
in your service directory. This file contains package-level functions for the APIs defined
as methods on the service struct. In the example above, you would see:
// Code generated by encore. DO NOT EDIT.
package email
import "context"
// These functions are automatically generated and maintained by Encore
// to simplify calling them from other services, as they were implemented as methods.
// They are automatically updated by Encore whenever your API endpoints change.
func Send(ctx context.Context, p *SendParams) error {
// The implementation is elided here, and generated at compile-time by Encore.
return nil
}
These functions are generated in order to allow other services to keep calling your
APIs as package-level functions, in the same way as before: email.Send(...)
.
This means other services do not need to care about whether you're using Dependency Injection
internally. You must always use these generated package-level functions for making API calls.
Please note
Encore will automatically generate these files and keep them up to date whenever your code changes. There is no need to manually invoke anything to regenerate this code.
Encore adds all encore.gen.go
files to your .gitignore
since you typically
don't want to commit them to your repository; doing so ends up creating
a lot of unnecessary merge conflicts.
However, in some cases when running third-party linters in a CI/CD environment
it can be helpful to generate these wrappers to make the linter happy.
You can do that by invoking encore gen wrappers
.
Graceful Shutdown
When defining a service struct, Encore supports notifying
your service when it's time to gracefully shut down. This works
by having your service struct implement the method
func (s *Service) Shutdown(force context.Context)
.
If that method exists, Encore will call it when it's time to begin gracefully shutting down. Initially the shutdown is in "graceful mode", which means that you have a few seconds to complete ongoing work.
The provided force
context is canceled when the graceful shutdown window
is over, and it's time to forcefully shut down. How much time you have
from when Shutdown
is called to when forceful shutdown begins depends on the
cloud provider and the underlying infrastructure. Typically it's in the range 5-30 seconds.
Please note
Encore automatically handles graceful shutdown of all Encore-managed functionality, such as HTTP servers, database connection pools, Pub/Sub message receivers, distributed tracing recorders, and so on.
The graceful shutdown functionality is provided if you have additional, non-Encore-related resources that need graceful shutdown.
Note that graceful shutdown in Encore is cooperative: Encore will wait indefinitely
for your Shutdown
method to return. If your Shutdown
method does not return promptly
after the force
context is closed, the underlying infrastructure at your cloud provider
will typically force-kill your service, which can lead to lingering connections and other
such issues.
In summary, when your Shutdown(force context.Context)
function is called:
- Immediately begin gracefully shutting down
- When the
force
context is canceled, you should forcefully shut down the resources that haven't yet completed their shutdown - Wait until the shutdown is complete before returning from the
Shutdown
function