context

package module
v0.0.0-...-edad312 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2023 License: MPL-2.0 Imports: 13 Imported by: 2

README

Dev module

The Dev module defines the interface of the service context. It also includes the definition of the development context. All contexts must have the interface defined in this module.

Warning

  • Tests sometimes fail due to downloading source code.
  • Tests fail due to firewall

Context

The context is the abstracted accessor to the hosting environment.

During the development, the service is hosted on the laptop. In production, a service maybe deployed to the cloud. On top of that, the service maybe containerized or stored as a binary.

All hosting options have different settings and features. Especially when it comes to service discovery and configuration. By abstracting the environment, the application is decoupled from the hosting. For each hosting provider, the context shall use the most optimized solutions.

The distributed systems could be hosted on multiple servers. The context abstracts the multiple machines.

Anything that service needs from the hosting environment comes from the context. Whether it's coming from the same server or remote server is not the worry of the service.

todo

Martin Fowler said this. For remote services the API must be coarsely grained.

Then, the AI must be able to create a coarsely grained API from smaller APIs. In order to solve it:

  • the proxy could be set using inproc protocol.
  • the proxy can have its own rule set.

For now, the context has.

  • The configuration engine.
  • The dependency manager.

Not implemented yet, but assume the file operations, networking and logging are also included in the context.

Todo

Add a network feature that allocates an address for the service.

Configuration engine

The configuration is not the part of the code. Thus, it comes from the hosting environment.

The configurations maybe passed in a different ways. As a file in json, ini or yaml formats. By third-party provider. For example, with etcd. The cloud providers also have their own configurations.

The task of the engine is to use the best solution with minimum setup in each environment.

More information about a configuration engine is available on config-lib.

Dependency manager

Todo

Problem: Dep services are attached to the current process. Closing the current process will close the running dependencies.

Solution: Spawn the child processes as the service. Use kardianos/service package.

Useful links:

The distributed systems must run all the services together. The services must be reliable and interconnected.

There are two approaches for managing distributed systems.

The first way is utilizing a separated tool. This tool is called an orchestrator. The popular orchestrators include kubernetes, docker compose.

The other way is to make an application self-orchestrating. Each service is responsible for reliability and discovery without an orchestrator. In my career as a coder, I did not encounter anyone who is doing by this approach. Because, self-orchestration adds a design complexity at the module level. Also, the code gets more complex as it includes a business logic and orchestration.

Using the orchestration tool, at the coding stage, a developer could focus on the business logic. Without worrying about orchestrating each part. However, the overall architecture is complex and requires more hardware resources. It also adds a centralization which creates a single point of failure. Self-orchestration has more benefits that over-comes the orchestration tools. It reduces the parts that service depends on. Finally, it makes the code-testable for inter-connection which is the hard task, actually.

SDS is the only framework that chose the second approach. By moving the orchestration part to the framework, the programmer doesn't have to write the tedious part.

Services relationships

To write the multithreading applications, there are programming languages with concurrency. The best example is Erlang. In this approach, the application could be imagined as a tree of the processes. A main thread spawns the child threads, sets up a message bus. If the parent process dies, then all child processes die along with it. If the child process dies, then the parent may respawn it again.

SDS framework works in the same way. There is a primary service with the application logic. Then, there are additional services that do a side work. The primary service is spawning additional services.

For example, the primary service could be an API. While the additional service could be a database driver.

In a more complex application, there are multiple layers of the services. The additional services may depend on other services as well.

In the example above, the database driver may depend on the authentication service.

In the SDS framework, a service manages the dependencies that have direct messaging with it. If the dependency has an own set of dependencies, then it's none of primary service businesses.

Again, refer to the config-lib


Dev Context

Which means it's in the current machine.

The dependencies are including the extensions and proxies.

How it works?

The orchestra is set up. It checks the folder. And if they are not existing, it will create them.

dev.Run(orchestra)

Then let's work on the extension. User is passing an extension url. The service is checking whether it exists in the data or not. If the service exists, it gets the yaml. And return the config.

If the service doesn't exist, it checks whether the service exists in the bin. If it exists, then it runs it with --build-config.

Then, if the service doesn't exist in the bin, it checks the source. If the source exists, then it will call go build. Then call bin file with the generated files.

Lastly, if a source doesn't exist, it will download the files from the repository using go-git. Then we build the binary. We generate config.

Lastly, the service.Run() will make sure that all binaries exist. If not, then it will create them.


The running the application will do the following. It checks the port of proxies is in use. If it's not, then it will call a run.

Then it will call itself.

The service will have a command to "shutdown" contexts. As well as "rebuild"


Dep Manager

Dep manager has sockets that work with the service. The reason is to reduce the logic in the service. Changing the dependencies is done by context. The dev manager without a socket will be synchronous. That means the service will be blocked until it finishes the dep process.

Now, the context will keep track of all dependencies and their management.

Documentation

Overview

Package context sets up the developer context.

Package config defines the specific parameters of the Contexts and Dev Context

Index

Constants

View Source
const (
	// SrcKey is the path of source directory from the configuration
	SrcKey = "SERVICE_DEPS_SRC"
	// BinKey is the path of bin directory from the configuration
	BinKey = "SERVICE_DEPS_BIN"
)

Specifically for Dev Context

Variables

This section is empty.

Functions

func SetDevDefaults

func SetDevDefaults(engine configClient.Interface) error

SetDevDefaults sets the required developer context's parameters in the configuration engine.

It sets the source manager's bin path and source path in (dot is current dir by executable):

	/bin.exe
	/_sds/source/
	/_sds/bin/
 /_sds/source/github.com.ahmetson.proxy-lib/main.go
 /_sds/bin/github.com.ahmetson.proxy-lib.exe

Types

type Context

type Context struct {
	// contains filtered or unexported fields
}

A Context handles the config of the contexts

func NewDev

func NewDev() (*Context, error)

NewDev creates Developer context. Loads it with the Dev Configuration and Dev DepManager Manager.

func (*Context) Close

func (ctx *Context) Close() error

Close the dep handler and config handler. The dep manager client is not closed

func (*Context) Config

func (ctx *Context) Config() configClient.Interface

Config returns the config engine in the context.

func (*Context) DepClient

func (ctx *Context) DepClient() dep_client.Interface

func (*Context) IsConfigRunning

func (ctx *Context) IsConfigRunning() bool

func (*Context) IsDepManagerRunning

func (ctx *Context) IsDepManagerRunning() bool

func (*Context) IsProxyHandlerRunning

func (ctx *Context) IsProxyHandlerRunning() bool

func (*Context) IsRunning

func (ctx *Context) IsRunning() bool

func (*Context) ProxyClient

func (ctx *Context) ProxyClient() proxy_client.Interface

ProxyClient returns the client that works with proxies

func (*Context) SetConfig

func (ctx *Context) SetConfig(socket configClient.Interface)

SetConfig sets the config engine of the given type. For the development context, it could be config-lib that reads the local file system.

Setting up the configuration prepares the context by creating directories.

func (*Context) SetDepClient

func (ctx *Context) SetDepClient(dc dep_client.Interface) error

func (*Context) SetProxyClient

func (ctx *Context) SetProxyClient(proxyClient proxy_client.Interface) error

SetProxyClient sets the client that works with proxies

func (*Context) SetService

func (ctx *Context) SetService(id string, url string)

SetService sets the service id and url for which this context belongs too.

func (*Context) StartConfig

func (ctx *Context) StartConfig() error

StartConfig starts the config engine.

func (*Context) StartDepManager

func (ctx *Context) StartDepManager() error

StartDepManager starts the dependency manager

func (*Context) StartProxyHandler

func (ctx *Context) StartProxyHandler() error

StartProxyHandler starts the proxy handler

func (*Context) Type

func (ctx *Context) Type() ContextType

Type returns the context type. Useful to identify contexts in the generic functions.

type ContextType

type ContextType = string
const (
	// DevContext indicates that all dependency proxies are in the local machine
	DevContext ContextType = "development"
	// UnknownContext indicates that the context is unspecified.
	UnknownContext ContextType = "unknown"

	ContextFlag = "context"
)

type Interface

type Interface interface {
	SetConfig(p configClient.Interface)
	Config() configClient.Interface
	SetProxyClient(p proxy_client.Interface) error
	ProxyClient() proxy_client.Interface
	Type() ContextType
	StartConfig() error
	StartDepManager() error
	StartProxyHandler() error
	Close() error // Close the dep handler and config handler. The dep manager client is not closed
	IsRunning() bool
	IsConfigRunning() bool
	IsDepManagerRunning() bool
	IsProxyHandlerRunning() bool
	SetService(string, string) // SetService sets the service parameters
	SetDepClient(p dep_client.Interface) error
	DepClient() dep_client.Interface
}

func New

func New(ctxTypes ...ContextType) (Interface, error)

A New orchestra. Optionally pass the type of the context. Or the context type could be retrieved from the config.ContextFlag.

Directories

Path Synopsis
Package dep_handler creates a thread that manages the dependencies
Package dep_handler creates a thread that manages the dependencies
Package dep_manager tracks the dependency manager in the local context.
Package dep_manager tracks the dependency manager in the local context.
Package proxy_client defines a client that works with the Proxy thread.
Package proxy_client defines a client that works with the Proxy thread.
Package proxy_handler is a thread that manages the service proxies
Package proxy_handler is a thread that manages the service proxies
Package source defines the dependency parameters in the 'dev' context.
Package source defines the dependency parameters in the 'dev' context.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL