An overview of the
In this article we will introduce the application entry to the Jupiter microservices framework. We wrote this article to gain insight into how the Jupiter framework works.
Introduction to Data Structure
Let’s look at Jupiter’s Application object,
// Application is the framework's instance, it contains the servers, workers, client and configuration settings.
// Create an instance of Application, by using &Application{}
// Entry structure for Jupiter framework
type Application struct {
cycle *xcycle.Cycle // Some function management that manages the runtime lifecycle
smu *sync.RWMutex
initOnce sync.Once
startupOnce sync.Once
stopOnce sync.Once
servers []server.Server // Various services, HTTP, GRPC, etc
workers []worker.Worker / / task
jobs map[string]job.Runner / / task
logger *xlog.Logger // Log object
registerer registry.Registry // The service registers the interface object
hooks map[uint32]*xdefer.DeferStack
configParser conf.Unmarshaller // System configuration object
disableMap map[Disable]bool
HideBanner bool
}
Copy the code
The Application object can be divided into the following components:
- Cycle, SMU, initOnce, startupOnce, stopOnce Help field about the running mechanism.
- The Servers, Workers, and Jobs fields are used to store various services, and the framework can start these services according to the same process as long as the service implements the interface.
- Registerer is the actual object of the service discovery and registration policy and can be ETCD, Consul, as long as the Registry interface is implemented.
- Hooks save individual hook functions at runtime of the framework
- The configParser field stores configuration information, which can be obtained from files or configuration center addresses.
- The Logger log object, the Xlog package, is a secondary modification of the ZAP log library.
The application process
In this section, we introduce the startup process of the framework. The flow chart is as follows:
The Application object is the Application entry to the Jupiter framework,
- SetRegistry() is used to inject service discovery and registration, such as the etcdv3 module in the Registry package.
- The Startup() method is the initialization method for each service.
- Serve(), Schedule(), and Job() are the injection methods for various services.
- RegisterHooks() are methods to RegisterHooks. For example, doing something before and after startup can be done through this method.
- The Run() method starts the application’s individual services and framework custom services, such as monitoring.
- Stop() is to perform some exit operations upon receiving a system signal.
Methods to introduce
The following are some of the main methods used to start the process.
Startup () method
//Startup Initialization method before application Startup
func (app *Application) Startup(fns ...func(a) error) error {
app.initialize() // Initialize the fields of the app
// Execute the initialization method defined by the framework
iferr := app.startup(); err ! =nil {
return err
}
// Perform a custom initialization method
return xgo.SerialUntilError(fns...)()
}
Copy the code
The Startup() method is equivalent to an Application initialization. Initialization consists of two parts, one of which is the initialization sequence defined by the framework, including parsing, starting and transmitting parameters, loading configurations, setting link tracing, traffic monitoring services, and service governance. The other part is the initialization of each service defined by the framework user. This part of the function is generally the call function of Serve(), Job(), Schedule() methods.
RegisterHooks () method
//RegisterHooks register a stage Hook
func (app *Application) RegisterHooks(k uint32, fns ...func(a) error) error {
hooks, ok := app.hooks[k]
if ok {
hooks.Push(fns...)
return nil
}
return fmt.Errorf("hook stage not found")}Copy the code
This method performs some of the framework’s hook methods, such as printing logs before and after startup.
The Run () method
// Run run application
// Apply the startup method
func (app *Application) Run(servers ... server.Server) error {
app.smu.Lock()
app.servers = append(app.servers, servers...)
app.smu.Unlock()
app.waitSignals() //start signal listen task in goroutine
defer app.clean()
// todo jobs not graceful
app.startJobs()
// start servers and govern server
app.cycle.Run(app.startServers)
// start workers
app.cycle.Run(app.startWorkers)
//blocking and wait quit
iferr := <-app.cycle.Wait(); err ! =nil {
app.logger.Error("jupiter shutdown with error", xlog.FieldMod(ecode.ModApp), xlog.FieldErr(err))
return err
}
app.logger.Info("shutdown jupiter, bye!", xlog.FieldMod(ecode.ModApp))
return nil
}
Copy the code
This method is the application startup method. The Run() method can be passed to objects that implement the Server.server interface. WaitSignals () starts a Goroutine to listen for system semaphores. Scheduled tasks, services (GRPC, HTTP, Govern), and task queues are started in sequence.
In this approach, the GRPC, HTTP, and Govern services register information for each service with the registry. Used for service discovery.
Stop () method
The Stop() method calls the shutdown method of each service to shut down and disconnect each service when the program exits.
Other articles
Article series
- Jupiter framework entry introduction
- GRPC through ETCD service discovery and registration – source code analysis
- Jupiter -etcd client introduction