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