Categorygithub.com/ahmetson/service-lib
repositorypackage
0.0.0-20231023183358-3f5b2d401d71
Repository: https://github.com/ahmetson/service-lib.git
Documentation: pkg.go.dev

# Packages

No description provided by the author
No description provided by the author

# README

Service

This is one of the core modules.

The service library allows creating of independent microservices.

We omit the micro prefix from now on.

The independent services are minimal stand-alone applications. A developer defines the list of API routes and a function that's executed.

The API routes are grouped into the handlers. The handler defines how the API is served to the external users.

The independent services are isolated from each other. They don't share a configuration nor the data that they are working on.

Application architecture

The application consists of multiple services.

The independent service is the core of the application. As it will keep the business logic.

There are auxiliary services.

The proxies that operate on a request before it's passed to a service. And extensions extending service possibility or do some side works.

One of the aims of SDS framework is to write self-orchestrating applications.

In the SDS framework, the services are organized in a parent-child relationship. The independent service acts as a root node. The auxiliary services counted as the child nodes.

That means the root node is responsible for spawning the children.

It's done in the background by the framework, so developers don't have to worry about it.

Coarsely grained API

When you define an API routes, you set them at the minimal level. But if the service is stored on another machine, then requesting data by minimal API will cause a delay.

In the microservice architecture, the remote APIs must be coarsely grained to reduce the network hops.

The extensions with merge flag can group the routes of the parent.

LifeCycle

When a service runs, it prepares itself. The preparation is composed of two steps. First, it creates a configuration based on the required parameters. Then, it fills them. If a user passed a pre-defined configuration, then the process will validate and apply them. If there is no configuration, then it will create a random configuration. That random configuration is written to the path.

When the service is prepared, it runs the manager. The manager is set in the "PREPARED" state. If the service has a parent service, then it will send the message to the parent.

After running the manager, the service runs the dependency manager. The dependency manager running means three things. If the service is running, it will ask to acknowledge the parent. Acknowledging the means to ask permission to connect from the parent. If the service is not acknowledged, it will mark that service as failed. If the service is not running, it will check the binary. If the binary exists, the service will run that binary. If the binary does not exist, the dependency manager will install it. Then run it. The dependency manager is working with the nearby proxies and extensions.

As a parent, it passes an id, configuration and its own id as a parent.

When the dependencies are all set, it updates the state to "READY". When some dependencies are not set, it will mark itself as "PARTIALLY_READY".

When it's (partially) ready, the dependency manager creates a heartbeat tracker. This tracker is given to the manager. Then, the manager creates its own heartbeat, and sends the messages to the parent. If no parent is given, it won't set it.

Usage

id := "application name"
s := service.New(id)
s.Prepare() // runs the manager
s.RunDepManager()
s.Run() // sets up

Service Lib

Service Lib is a library to create services on SDS.

SDS is the protocol, libraries, and an account system. The aim of it to create meaningful services and also useful for other developers.

The account system consists of the API service authentication and payment system.

Contents


Components

Service

A service is a solution for a one problem as an independent software. An app is an interconnection of the services.

Since services are independent software, then, an app will be considered as a distributed system.

Single service itself also acts as an app. Here, we just refer as app to the specific business case of your need.

The services are created using Service Lib. The goal of Service Lib is to write re-usable solutions that will be useful to another project with a minimal setup. Hence, why the services are standalone applications .

To compose an app from the services in a structured way, the services are divided into three categories.

Independent

The first type of the services are independent services. Read it as an independent software. Your app should have one independent service that keeps the core logic of your application.

Independent services will rarely be shared. So the source code could be private.

Extension

The second type of the services are extension services. The extensions are the solutions that could be re-used by multiple projects.

This is the core part that all makes the services as re-usable.

The extensions are allowed to be connected from the independent services. And doesn't work with the users directly.

Proxy

The third and last type of the services are proxy services. The proxy acts as a switch between a user/service and a user/service. Depending on the proxy result the request will be forwarded or returned back to the client.


Controller

Since the services are the units of distributed system, services has to talk to each other. And services has to talk with the external world.

Therefore, each service acts as a server. The service mechanism transfers in or out some messages. This mechanism is implemented through controllers.

Controller is an alias of server.

Controller term comes from the MPC pattern.

A service may have multiple controllers, at least one. The controllers receive the messages. Then controller is routing the messages to the handlers. To find the right handler, the messages include the commands.

For optimization needs, there are different kinds of controllers.

Replier

A replier controller handles a one request at a time. All incoming requests are queued internally, until the current request is not executed. When the request is executed, the controller returns the status to the callee. Then replier will execute the next request in the queue.

The requester will be waiting the response of the controller

Router

A router controller handles many requests at a time. Upon the execution, the router will reply the status back to the callee.

The requester will be waiting the response of the controller

Puller

A puller controller handles a one request at a time. All requests will be queued internally. When the controller finishes the execution, it will execute the next request in the queue.

Puller will not respond back to the callee about the status.

The requester will not wait for the response of the controller. So this one is faster.

Publisher

A publisher controller sends messages to the subscribers. It doesn't receive the request from outside. But has internal puller controller that the publisher is connected too. Any message coming into the puller invokes mass message broadcast by the publisher.

The subscriber waits for the controller, but doesn't request to the publisher. The invoker of the puller doesn't wait for the response of the publisher.


Configuration

Any apps created by this module is loading environment variables by default.

As well as it requires the configuration in yaml format.

Env

You can set the Yaml file name as well as it's path using the following environment variables:

SERVICE_CONFIG_NAME=service
SERVICE_CONFIG_PATH=.

By default, the service will look for service.yml in the . directory.

Yaml

The configuration format is this:

Services:
  - Type: Independent # or Proxy | Extension
    Name: 
    Instance: 
    Controllers:
      - Type: Replier # or Puller | Publisher | Router
        Name: "myApi"
        Instances:
          - Port: 2302
            Instance: 
    Proxies:
      - Name: "auth"
        Port: 8000

    Pipelines:
      - "auth->myApi"

    Extensions:
      - Name: "database"
        Port: 8002

At root, it has Services with at least one Service defined. The service has the following parameters:

  • Type which defines what kind of service it is. It could be Independent, Proxy or Extension.
  • Name of the service. If you define multiple services, then their Type and Name should match.
  • Instance is the unique identifier of this service. If you have multiple services, then it should have different instance.
  • Controllers lists what kind of command handlers it has.
  • Proxies lists what kind of proxies it has.
  • Pipelines should have one or more proxy pipeline. The last name should name of the controller instance.
  • Extensions lists the extensions that this service depends on. All these extensions are passed to the controllers.

The controllers are the command handlers. All incoming requests from the users (whether it's through proxy or not) are handled by the controllers. The parameters of the controllers:

  • Type which defines what kind of controller it is. It could be Replier, Puller, Publisher or Router.
  • Name of the controller to classify it.
  • Instances describes the unique controllers of this type.

The controller instances have the following parameters:

  • Instance is the unique id of the controller within all service
  • Port where the controller exposes itself

Proxy has the following parameters:

  • Name of the proxy
  • Port where the proxy set too.

Extension has the following parameters:

  • Name of the extension
  • Port where the extension set too.

Flags

The built service will have several flags and arguments.

  • --secure enables authentication
  • --generate-config rather than starting, it will create a default yaml configuration
  • --path=./a.yml relative path of the generated configuration. The value should end with .yml.
  • --configuration=./b.yml relative path of the configuration to use.

Further reading

Once you understand the Services, go read further to create different kinds of services.