# README

![Orbit Logo](https://www.orbit.cloud/img/orbit-logo-black.png)

[![Build Status](https://github.com/orbit/orbit/workflows/Build%20Orbit/badge.svg)](https://github.com/orbit/orbit/actions) [![Release](https://img.shields.io/github/release/orbit/orbit.svg)](https://github.com/orbit/orbit/releases) [![Maven Central](https://img.shields.io/maven-central/v/cloud.orbit/orbit-server.svg)](https://repo1.maven.org/maven2/cloud/orbit/) [![Documentation Status](https://img.shields.io/badge/docs-passing-brightgreen.svg)](https://docs.orbit.cloud/)

## Full Documentation

See the [documentation website](https://www.orbit.cloud/orbit/) for full documentation, examples and other information.

## Orbit 1

Looking for Orbit 1? Visit the [orbit1](https://github.com/orbit-legacy/orbit1) legacy project.

## Developer & License

This project was developed by [Electronic Arts](http://www.ea.com) and is licensed under the [BSD 3-Clause License](https://github.com/orbit/orbit/tree/0346fa18458ffd671fd852c0055b014333358e59/LICENSE/README.md).


# docs


# content


# getting-started


# actors

Actors are the most common form of addressable and are suitable for most situations. The distinction is semantic and Actor interfaces are provided to facilitate the actor pattern.

Actors are never created or destroyed; they always exist conceptually. Not all actors in Orbit will be in-memory in the cluster at a given time. Actors which are in-memory are considered “activated” and those which are not are “deactivated”. The process of an actor being created in-memory is known as “Activation” and the process of an actor being removed from memory is known as “Deactivation”.

When a message is sent to an inactive actor, it will be placed somewhere in the pool of connected servers and activated. During the activation process, the actor’s state can be restored from a database. Actors are deactivated based on activity timeouts or server resource usage. Actor state can be persisted at any time or upon deactivation.

## Actors

Just like with an Addressable, Actors are defined by interfaces and implementations.

```kotlin
package orbit.carnival.actors

import orbit.client.actor.ActorWithStringKey
import orbit.client.actor.AbstractActor

interface Game : ActorWithStringKey {
    suspend fun play(playerId: String): PlayedGameResult
}

class GameImpl() : AbstractActor(), Game {
{
    override suspend fun play(playerId: String): PlayedGameResult {
        ... Game code
    }
}
```

## Calling

Actors are called via a proxy. A proxy is created via the Orbit runtime context, typically Stage or AddressableContext.

### Accessing the Proxy Factory

**Kotlin**

```kotlin
// Via Orbit Client
orbit.actorFactory.createProxy<Greeter>()

// From an Addressable
context.client.actorFactory.createProxy<Greeter>()
```

**Java**

```java
// Via Orbit Client
orbit.getActorFactory().createProxy(Greeter.class);

// From an Addressable
getContext().getClient().getActorFactory().createProxy(Greeter.class);
```

## Runtime Model

Orbit guarantees that only one activation of an actor with a given identity can exist at any one time in the cluster by default. As such, developers do not need to be concerned about keeping multiple activations/instances of an actor synchronized with one another.

By default, Orbit also guarantees that calls to actors can never be processed in parallel using safe execution mode. This means that developers do not need to worry about concurrent access to an actor. Two calls to an actor can not be processed in parallel.

## Keys

Like all addressables, every actor in Orbit has a key. Additionally, to ensure they are type safe every actor interface must choose only one key type, this is achieved by extending one of the following actor interfaces. An example of how this works can be seen below.

| Actor Interface    | JDK Type | Orbit Type |
| ------------------ | -------- | ---------- |
| ActorWithNoKey     | N/A      | NoKey      |
| ActorWithStringKey | String   | StringKey  |
| ActorWithInt32Key  | Integer  | Int32Key   |
| ActorWithInt64Key  | Long     | Int64Key   |


# prerequisites

## Required Software

The minimum requirements for an Orbit client application.

* [Java 11 SE SDK](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html) or above.
* [Gradle](https://gradle.org/install/)
* [Kotlin](https://kotlinlang.org/)

## Orbit Server

To run an Orbit Server inside a Docker environment

* [Docker Desktop](https://www.docker.com/products/docker-desktop)
* [Docker Compose](https://docs.docker.com/compose/install/)

## Recommended Software

* [IntelliJ IDEA](https://www.jetbrains.com/idea/) is our preferred IDE.


# migration-from-1.x

## Orbit 2 Philosophy

Orbit 2 accomplishes the same basic goals as Orbit 1.x, but via a whole different approach. Orbit 1.x takes the form of a component included in an application utilizing distributed storage to coordinate messaging between service instances. Orbit 2 has taken all the responsibilities of tracking Actors and routing messaging into a standalone, scalable, and multi-tenant mesh service. Applications connect to the mesh over GRPC through a thin client library that manages the connection, leasing, and message delivery.

This change in overall design leads to greater reliability, fault tolerance, scalability, and helps with ZDT deployment.

## New concepts

### Addressables

Actors are still very much a first-class focus of Orbit 2, but have been designed as part of a higher level of abstraction. Addressables are the core message target, with Actors as a special case. An Addressable is any entity that can receive a message.

Read more about [Addressables](https://github.com/orbit/orbit/tree/03de01d5a629c8606cd109b85a8a3714491d7c67/getting-started/addressables/README.md)

### Orbit Client

Integrating Orbit Client into your application is the easiest way to work with the Orbit Server Mesh. It handles connecting to the Orbit Server mesh, manages the lifetime of the connection, and helps easily send and receive messages to Addressables anywhere.

Read more about [Orbit Client](https://github.com/orbit/orbit/tree/03de01d5a629c8606cd109b85a8a3714491d7c67/client/README.md)

## Outdated concepts

### Stage

The stage has been deprecated in favor of the simpler interface of the Orbit Client.

## Future functional parity

Some features of Orbit 1.x have not yet made it into Orbit 2, but will be prioritized based on need and available development time.

### Streams

### Extensions

### Reentrancy

### Placement group?


# hello-world

In this guide we’ll cover how to get a very simple Orbit application running in the form of “Hello World”. It shows using a single-module in a single-process environment, often useful for development purposes. This will demonstrate how to set up an Actor and communicate with an Orbit Server.

This tutorial assumes that you have set up a development environment as described in the [Getting Started Prerequisites](https://github.com/orbit/orbit/tree/233956001f1206ccbfde72efb0eab8479761951e/getting-started/prerequisites/README.md) document and have some familiarity with Gradle based Kotlin projects. All samples are in Kotlin, the language in which Orbit is developed, but the principles work for a Java app as well.

## Gradle Project

The first step is to set up a Gradle project and pull in the Orbit dependencies.

```
implementation("cloud.orbit:orbit-client:{{< release >}}")
```

## Actor Interface

In Orbit all actors must have an interface, below we’ll create a very simple actor interface.

**greeter.kt**

```kotlin
package orbit.hello

import orbit.client.actor.ActorWithStringKey

interface Greeter : ActorWithStringKey {
    suspend fun sayHello(): String
}
```

* Actor interfaces are standard Kotlin interfaces with special constraints
* All Actor interfaces must extend an Actor type
* All interface methods must return a future in the form of a Deferred or be a suspending Kotlin method
* The return type must be serializable or Unit.

## Actor Implementation

Once you have an actor interface in place, the final step to complete the actor is to create an actor implementation.

**greeterImpl.kt**

```kotlin
package orbit.hello

import orbit.client.actor.AbstractActor

class GreeterImpl : AbstractActor(), Player {
{
    override suspend fun sayHello(greeting: String): String {
    {
        println("Here: ${greeting}")
        return "You said: '${greeting}', I say: 'Hello from ${context.reference.key} at node ${context.client.nodeId?.key}!'")
    }
}
```

* An actor implementation is a standard Kotlin or Java class
* Extending AbstractActor grants access to the context with a reference to client and the actor's address
* The actor must implement an actor interface
* Only one actor implementation per actor interface is permitted

## Using The Actor

The final step to get a working example is for us to actually use the actor.

**app.kt**

```kotlin
package orbit.hello

import kotlinx.coroutines.runBlocking
import orbit.client.OrbitClient
import orbit.client.OrbitClientConfig

fun main() {
    runBlocking {
        val orbitClient = OrbitClient(
            OrbitClientConfig(
                namespace = "hello",
                grpcEndpoint = "dns:///localhost:50056/"
            )
        )

        orbitClient.start().join()

        val greeter = orbitClient.actorFactory.createProxy(Greeter::class.java, "Tim");
        val response = greeter.sayHello("Welcome to Orbit");

        println(response)

        orbitClient.stop().join()
    }
}
```

* We create an orbit client instance in our namespace "hello"
* We get a reference to an actor
* The framework will handle the activation of the actor.
* You can communicate with the actor without knowing it's status.

## Running Orbit Server

Assure Docker Desktop is running and Docker Compose is installed from the [Prerequisites](https://github.com/orbit/orbit/tree/233956001f1206ccbfde72efb0eab8479761951e/getting-started/prerequisites/README.md) step.

In a terminal window, run the following.

\`\`\`shell script

> docker run -it -p 50056:50056 orbitframework/orbit: Listening for transport dt\_socket at address: 5005 \[main] INFO orbit.application.impl.SettingsLoader - Searching for Orbit Settings... \[main] INFO orbit.application.impl.SettingsLoader - No settings found. Using defaults. \[main] INFO orbit.server.mesh.local.LocalMeterRegistry - Starting simple meter registry \[orbit-cpu-1] INFO orbit.server.OrbitServer - Starting Orbit server... \[orbit-cpu-1] INFO orbit.server.OrbitServer - Lease expirations: Addressable: 600s, Node: 10s \[orbit-cpu-1] INFO orbit.server.pipeline.Pipeline - Started a rail worker with 32 rails and a 10000 entry buffer. \[orbit-cpu-1] INFO orbit.server.mesh.LocalNodeInfo - Joined cluster as (NodeId(key=aFmxt6MWvWP5HihR, namespace=management)) \[orbit-cpu-1] INFO orbit.server.service.GrpcEndpoint - Starting gRPC Endpoint on LocalServerInfo(port=50056, url=localhost:50056).port... \[orbit-cpu-1] INFO orbit.server.service.GrpcEndpoint - gRPC Endpoint started on LocalServerInfo(port=50056, url=localhost:50056).port. \[orbit-cpu-1] INFO orbit.server.OrbitServer - Orbit server started successfully in 338ms. \`\`\`

## Running

You should now be able to run the project. If everything has gone well, you should see output similar to the following:

```
Connecting to Orbit at dns:///localhost:50056/
Here: Welcome to Orbit
You said: 'Welcome to Orbit!', I say: Hello from Tim at node aFmxt6MWvWP5HihR!
```

Congratulations, you have created your first Orbit application!


# \_index

## Hello World

For a demonstration of the basic concepts of Orbit, check out the Hello World page. It will show how to implement and wire up your first actor.

## Carnival Sample App

For a demonstration beyond the basics, we have a more advanced ["Carnival"](https://github.com/orbit/orbit-sample) sample application which implements a REST service over some actors, running against a Kubernetes-hosted Orbit Server.


# modules

The Orbit project is split into several modules for client and server.

## Client

### orbit-client

A JVM library for applications interfacing with an Orbit cluster. It handles maintaining a connection to the mesh, leasing addressables, and routing messages. It will be the main entrypoint for most developers.

To include in your Gradle project, import the client library.

```kotlin
implementation("cloud.orbit:orbit-client:{{< release >}}")
```

## Server

Orbit can be run as a packaged service without having to delve into the server modules. However, if a more customized version of Orbit is needed, these modules can be used to build the server suitable to the task.

### orbit-server

This is the main implementation of the Orbit Server cluster node. It handles the client connections, mesh connections, authorization, node and addressable leases, and message routing.

### orbit-application

Default hosting application for orbit-server. Decodes settings from a file and initiates the server runtime.

### orbit-proto

Contains the protobuf definitions for communicating with the service and helper methods for translation to internal types.

### orbit-server-etcd

Implementations of the Node Directory and Addressable Directory against an etcd store. By default orbit-server will use in-memory directories, but those won't support clustering multiple Orbit Server nodes nor will values persist between restarts.

### orbit-server-prometheus

Implementation of a Prometheus endpoint for exposing metrics gathered by [micrometer](https://micrometer.io).

### orbit-shared & orbit-util

Shared and utility classes mostly to support internal operations.


# addressables

In Orbit, an addressable is an object that interacts with the world through asynchronous messages. Simply, it has an address and can receive messages, even remotely.

Orbit will activate an addressable when it receives a message, and deactivate it when after a configurable period of inactivity. This patterns allows developers to speed up interactions and reduce load on databases and external services.

Orbit guarantees that only one addressable with a given identity can be active at any time in the cluster. As such, developers do not need to be concerned about keeping multiple activations/instances of an addressable synchronized with one another.

Orbit also guarantees that calls to addressables can never be processed in parallel, meaning developers do not need to worry about concurrent access to an addressable. Two calls to an addressable can not be processed in parallel.

## Addressable Interfaces

Before you can implement an addressable you must create an interface for it.

#### Using a suspend method

```kotlin
package sample.addressables

import orbit.client.addressable.Addresable

interface Greeter : Addressable {
    suspend fun hello(message: String): String
}
```

#### Using a Kotlin future

```kotlin
package sample.addressables

import kotlinx.coroutines.Deferred
import orbit.client.addressable.Addresable

interface Greeter : Addressable {
    fun hello(message: String): Deferred<String>
}
```

## Asynchronous Return Types

Addressables must only contain methods which return asynchronous types, like futures, or be Kotlin suspending methods. The following return types (and their subtypes) are currently supported.

| Main Type                                                                                                     | Common Subtypes                                                                                                                      | For    |
| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------ |
| [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/) | [CompletableDeferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-completable-deferred/) | Kotlin |
| [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)        | [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)                           | JDK8+  |
| [Suspend](https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html)               | N/A                                                                                                                                  | Kotlin |

## Concrete Implementation

Once you have created an Addressable interface, you must offer an implementation for Orbit to use. For each addressable interface, exactly one addressable class must implement it.

#### Using suspending methods

```kotlin
package sample.addressables

import orbit.client.addressables.AbstractAddressable
import sample.addressables.Greeter

class GreeterImpl() : AbstractAddressable(), Greeter {
{
    override suspend fun hello(message: String): String {
        return "Message: ${message}"
    }
}
```

#### Using a Kotlin future

```kotlin
package sample.addressables

import kotlinx.coroutines.Deferred
import kotlinx.coroutines.CompletableDeferred
import orbit.client.addressables.AbstractAddressable
import sample.addressables.Greeter

class GreeterImpl() : AbstractAddressable(), Greeter {
{
    override fun hello(message: String): Deferred<String> {
        return CompletableDeferred("Message: ${message}")
    }
}
```

## Lifetime

When a message is sent to a given addressable reference, the framework will perform the following actions:

1. Check if the addressable is already activated in the cluster
   * If so, forward the message to the client
   * If not, proceed to step 2
2. Activate the addressable for the addressable type and place on a connected client
3. Call the OnActivate hook to initialize any state, such as restoring from persistence
4. Forward the message to the addressable

Orbit does not provide any default persistence functionality, but the `@OnActivate` hook is available to restore state from a store before it receives the message.

```kotlin
class GreeterImpl() : AbstractAddressable(), Game {
{
    @OnActivate
    suspend fun onActivate() {
        loadFromStore()
    }

    @OnDeactivate
    suspend fun onDeactivate(deactivationReason: DeactivationReason) {
        saveToStore()
    }
}
```

Addressables can be persisted at any time, but the @OnDeactivate hook can help assure the latest state is saved, except in the event of an hard shutdown. During graceful shutdown, every actor is deactivated giving it a final chance to persist. Activate and Deactivate methods can similarly utilize a future by returning a `Deferred<Unit>`.

## Execution Model

Addressables in Orbit can have multiple different execution modes. By default, addressables will use Safe Execution Mode.

### Safe Execution Mode

In safe execution mode Orbit guarantees that calls to addressables can never be processed in parallel. This means that if two clients call an addressable at the same time, they are guaranteed to be processed serially (one after the other) where one call completes before the next one starts.

Orbit guarantees "at most once" delivery, meaning that best attempts will be made to deliver a message one time, but will deliver an error upon failure to deliver.

## Context

If an Addressable extends the AbstractAddressable or AbstractActor class, it will have access to an Orbit-managed context object. The AddressableContext provides access to the AddressableReference (identifier) and the OrbitClient instance. The AddressableReference can be used during the @OnActivate hook to identify which addressable needs to be restored from persistence.

```kotlin
abstract class AbstractAddressable {
    lateinit var context: AddressableContext
}

data class AddressableContext(
    val reference: AddressableReference,
    val client: OrbitClient
)
```

For example, if the addressable is an Actor with a String-type key,

```kotlin
interface IdentityActor : ActorWithStringKey {
    suspend fun identity(): String
}

class IdentityActorImpl() : IdentityActor, AbstractActor() {
    override suspend fun identity(): String {
        val id = context.reference
        return context.actorFactory.createProxy<IdentityResolver>().resolve(id)
    }
}
```

## Keys

Every addressable in Orbit has a unique key of one of the following types which identifies it.

| Orbit Type | JDK Type |
| ---------- | -------- |
| NoKey      | N/A      |
| StringKey  | String   |
| Int32Key   | Integer  |
| Int64Key   | Long     |


# contributing


# legal

## Software License

Orbit is licensed under the BSD 3-clause license. See it [here](https://github.com/orbit/orbit/blob/next/LICENSE).

## Contributor License Agreement

Like many other open source projects we require contributors to agree to our Contributor License Agreement (CLA) which can be found [here](https://github.com/orbit/orbit/blob/master/CONTRIBUTING.md).


# Project Control

The Orbit project is currently controlled and maintained by [Electronic Arts](https://www.ea.com) (EA).

As an Open Source project we welcome contributions from everyone. The final decision for changes being accepted into Orbit is taken by the Project Maintainer (currently [Joe Hegarty](https://github.com/joehegarty)).


# Coding Standards

Orbit adheres to the standard Kotlin Style Guide / Coding Conventions which can be found [here](https://kotlinlang.org/docs/reference/coding-conventions.html).


# \_index

While the Orbit project is primarily developed and maintained by [Electronic Arts](https://www.ea.com) (EA), it welcomes contributions to the community.


# \_index

## What is Orbit?

Orbit is a framework to write distributed systems using virtual actors on the JVM. A virtual actor is an object that interacts with the world using asynchronous messages.

At any time an actor may be active or inactive. Usually the state of an inactive actor will reside in the database. When a message is sent to an inactive actor it will be activated somewhere in the pool of backend servers. During the activation process the actor's state is read from the database.

Actors are deactivated based on timeout and on server resource usage.

It is heavily inspired by the [Microsoft Orleans](https://github.com/dotnet/Orleans) project.

## Documentation

The Orbit documentation is located on this site. Please see the sidebar for navigation.

## Source Code & Other Projects

The core orbit framework and runtime code is located in the [orbit/orbit](https://github.com/orbit/orbit) project.

## Sample Application

A sample application has been built to demonstrate the most common scenarios for integrating with an Orbit Server at [orbit/orbit-sample](https://github.com/orbit/orbit-sample)


# client


# configuration

Orbit Client offers a broad set of configuration options to be supplied in its constructor. Some settings are required to discover addressables and connect to an Orbit Server cluster, while others can fine-tune how the client operates.

The `OrbitClientConfig` class contains the configuration values the `OrbitClient` needs to operate and is supplied in the constructor:

```kotlin
import orbit.client.OrbitClient
import orbit.client.OrbitClientConfig

fun main() {
    runBlocking {
        val orbitClient = OrbitClient(
            OrbitClientConfig(
                namespace = "carnival",
                grpcEndpoint = "dns:///localhost:50056/",
                ...
            )
        )
        orbitClient.start().join()
    }
}
```

## Required fields

### `namespace: String`

The namespace to use when connecting to the Orbit cluster. This namespace will identify all the client nodes as part of a system, isolated from any other namespaces. Care must be taken if multiple independent deployments utilize the same Orbit services so that the namespaces they use don't intersect. This will result in confusion as addressables are activated in unexpected places.

### `grpcEndpoint: String`

The gRPC endpoint where the Orbit server cluster is located. Should be of the form `dns:///<host>:<port>/`.

## Interesting optional fields

### `packages: List<String>`

Packages to scan for addressables. If left blank, all packages will be scanned. Example:

```
    packages = listOf("orbit.carnival.actors")
```

### `addressableTTL: Duration`

Time To Live (TTL) for addressables before client deactivation.

### `addressableConstructor: ExternallyConfigured<AddressableConstructor>`

The system to use to construct addressables. The default value calls the addressable's default empty constructor. More information on bringing your own DI can be found in the [Dependency Injection](https://github.com/orbit/orbit/tree/158437bedd63703c424146229e98ea76d54a92c4/client/dependency-injection/README.md) section.

### `platformExceptions: Boolean`

Rethrow platform specific exceptions. Note: Should only be used when all clients are using the same SDK.

### `containerOverrides: ComponentContainerRoot.() -> Unit`

Hook to update internal container registrations after initialization. Example:

```
    containerOverrides = {
        instance(kodein)
        instance(sqlDatabaseAdapter)
        definition<HealthService>()
    }
```

### `bufferCount: Int`

The number of messages (inbound) that may be queued before new messages are rejected. This applies back pressure protection to prevent being overwhelmed with incoming messages.


# shutdown

Orbit is designed to handle a graceful or hard shutdown.

In a hard shutdown scenario, Orbit servers will notice a client node disconnecting the GRPC connection and suspend the leases on all addressables placed on that node. Any subsequent messages will be routed to new nodes where the addressables become activated. There may be some message loss during this brief transition period.

Orbit also affords an opportunity for a graceful shutdown through a shutdown procedure that can be invoked by the client application.

By calling `.stop()` on the Orbit Client instance, Orbit will deactivate all the actors placed on this node so they can be

```kotlin
orbitClient.stop()
```

In a Kotlin application, this can be used in conjunction with a SIGTERM handler to automatically clean up on any graceful application exit.

```kotlin
Runtime.getRuntime().addShutdownHook(object : Thread() {
    override fun run() = runBlocking {
        println("Gracefully shutting down")
        orbitClient.stop().join()
        println("Shutdown complete")
    }
})
```

When `.stop()` is called, the Orbit Client will go through the following procedure.

1. System signals to the client application a shutdown (SIGTERM)
2. Application calls `orbitClient.stop()` and waits for it to return
   * Orbit Client tells the server to remove the client node from the pool for addressable placement
   * Orbit Client iterates through all addressables placed on this node
     * Calls the OnDeactivate method on the addressable, if specified, to perform any cleanup
     * Abandons the lease with the Orbit service
3. Application completes its shutdown

Notes:

* Ideally, client applications should be built around actors persisting their state on write, so there is nothing left to do on shutdown. But in rare cases where that's required, this option is available.
* A graceful shutdown will likely lead to less message loss than a hard shutdown.
* Any messages in-flight to an addressable on the shutting down node will still be delivered until the addressable is deactivating. This can be handy if graceful shutdown with many addressables and a costly deactivation cause shutdown to last seconds or minutes.

## Deactivation Modes

There are 4 available modes for deactivation, reflecting different scenarios.

### Instant

This is the default mode of operation. Orbit client will call to deactivate the addressables as fast as possible. This is suitable for scenarios where there is no need to persist to a potentially bottlenecked resource such as a database, and there is no expectation another client node reactivating the addressables will put any undue strain on a resource.

```
OrbitClientConfig(
    ...
    addressableDeactivator = AddressableDeactivator.Instant.Config()
)
```

### Concurrent

This lets the number of deactivations be limited to a set number occurring simultaneously. This is useful for cases where some resource like database connections in a pool needs to be protected from a flood of last-minute writes.

```
OrbitClientConfig(
    ...
    addressableDeactivator = AddressableDeactivator.Concurrent.Config(concurrentDeactivations = 20)
)
```

### Rate Limited

This controls the number of deactivations initiated per second, regardless of how long they take. This is for scenarios where either deactivation or reactivation on a new host needs to be controlled at a sustainable rate.

```
OrbitClientConfig(
    ...
    addressableDeactivator = AddressableDeactivator.RateLimited.Config(deactivationsPerSecond = 100)
)
```

### Time Span

Similar to rate limiting, but spreads the deactivations over a number of milliseconds, regardless of the number of active addressables.

```
OrbitClientConfig(
    ...
    addressableDeactivator = AddressableDeactivator.TimeSpan.Config(deactivationTimeMilliseconds = 10000)
)
```

## Overriding deactivation mode

In some cases it's not guaranteed that the configured deactivation mode is desired, like if a hard shutdown is required in some cases. An addressable deactivation method can be specified when shutting down the client by passing it into the `orbitClient.stop()` method.

```
orbitClient.stop(
    deactivator = AddressableDeactivator.TimeSpan(AddressableDeactivator.TimeSpan.Config(10000))
)
```

## SIGTERM Caveat

The method described above to hook shutdown into SIGTERM is the simplest solution that handles most situations. Detaching a debugger, Ctrl-C from the command line, or shutting down a Docker container all invoke this path.

In a larger application, the time to gracefully drain all actors and shut down could take seconds or minutes. If there are system constraints that timeout before sending a SIGKILL, the graceful shutdown could be incomplete.

Additionally, in more complicated applications, many components could be listening for the SIGTERM event leading to non-determinism in tearing the application down. For example, metrics services may be shut off before the drain is complete, leaving the larger environment blind to the application's inner state.

It is up to the application developer to balance these concerns and determine the best way to tear down the application.


# dependency-injection

By default, Orbit will instantiate and activate Addressables using the default, empty constructor. Many times an Addressable will require some service or store for activation or its functional use.

Orbit supports a "bring your own DI container" model

The typical approach is to use constructor dependency injection, where dependencies are be supplied as constructor arguments.

```kotlin
class PlayerImpl(private val playerStore: PlayerStore) : AbstractActor(), Player {
    ... PlayerImpl code
}
```

To wire a DI container into Orbit, the `addressableConstructor` member of `OrbitConfig` can be replaced with a custom implementation of the `AddressableConstructor` interface. Below is an example

```kotlin
class KodeinAddressableConstructor(private val kodein: Kodein) : AddressableConstructor {
    object KodeinAddressableConstructorSingleton : ExternallyConfigured<AddressableConstructor> {
        override val instanceType = KodeinAddressableConstructor::class.java
    }

    override fun constructAddressable(clazz: Class<out Addressable>): Addressable {
        val addressable: Addressable by kodein.Instance(TT(clazz))

        return addressable
    }
}
```

In this case, the `KodeinAddressableConstructor` requires a Kodein instance in its constructor. The instance can be supplied to the internal Orbit container through the `containerOverrides` member of OrbitConfig which will supply it automatically when the `KodeinAddressableConstructor` is created.

```kotlin
import orbit.carnival.actors.PlayerImpl
import orbit.carnival.actors.repository.PlayerStore
import orbit.carnival.actors.repository.etcd.EtcdPlayerStore
import org.kodein.di.*
import org.kodein.di.generic.*

fun main() {
    runBlocking {
        ...
        val kodein = Kodein {
            bind<PlayerStore>() with singleton { EtcdPlayerStore(storeUrl) }
            bind<PlayerImpl>() with provider { PlayerImpl(instance()) }
        }

        val orbitClient = OrbitClient(
            OrbitClientConfig(
                ...
                addressableConstructor = KodeinAddressableConstructor.KodeinAddressableConstructorSingleton,
                containerOverrides = {
                    instance(kodein)
                }
            )
        )
        ...
    }
}
```


# \_index

Orbit Client is the easiest entrypoint for your JVM application to into Orbit. It handles connecting to the Orbit Server mesh, manages the lifetime of the connection, and helps easily send and receive messages to Addressables anywhere.


# server


# hosting

Almost any scenario can be handled by using the prepackaged Orbit Server. For scenarios where the developer needs extensive control over the server, Orbit functionality can be hosted within a custom application.

Describe taking a reference to orbit-server, starting an instance. Role of orbit-application.

Gradle:

```kotlin
implementation("cloud.orbit:orbit-server:{{< release >}}")
```

To instantiate an OrbitServer:

```kotlin
import kotlinx.coroutines.runBlocking
import orbit.server.OrbitServerConfig
import orbit.server.OrbitServer

fun main() {
    runBlocking {
        val server = OrbitServer(OrbitServerConfig(
            ... configuration
        ))
        server.start().join()
    }
}
```

## OrbitServerConfig

The `OrbitServerConfig` class can be used to make changes to server configurations, including things like lease times, persistence technology, resource limitations, and metrics.


# \_index

Orbit Server can be run right out of the box, with several easy ways to get started.

## Docker container

The simplest way to start an Orbit Server for development is in a Docker container from the Docker Hub [image](https://hub.docker.com/r/orbitframework/orbit).

\`\`\`shell script

> docker run -it -p 50056:50056 orbitframework/orbit: \`\`\`

## Kubernetes

Orbit Server comes packaged as a helm chart hosted on Github. Include Orbit Server as a dependency in your application's helm charts.

```yaml
dependencies:
- name: orbit
  version: {{< release >}}
  repository: https://www.orbit.cloud/orbit
  condition: enabled
```

To configure Orbit, set overrides in a values.yaml file or use the --setValues switches when running `helm install`.

```yaml
orbit:
  url: localhost
  node:
    replicas: 1
    containerPort: 50056
  addressableDirectory:
    replicas: 1
  nodeDirectory:
    replicas: 1
```

## Hosted

Most scenarios are supported with the turnkey methods above. For some advanced situations, it may be preferred to host the Orbit Server runtime within an existing server application.

For help on hosting Orbit Server, check out the [Hosting](https://github.com/orbit/orbit/tree/03de01d5a629c8606cd109b85a8a3714491d7c67/server/hosting/README.md) page.

The best example of hosting the Orbit Server components can be found in the [**orbit-application**](https://github.com/orbit/orbit/blob/master/src/orbit-application/src/main/kotlin/orbit/application/App.kt) module.


# configuration

Orbit Server offers extensive configuration and an extension model to support many situations outside the defaults. The `OrbitServerConfig` class supplied to the `OrbitServer` constructor has overrides for lease timing, process management, addressable and node storage, and metrics.

The `OrbitServerConfig` class is well documented and will be the authoritative source for the latest options. Some settings, like the `pipelineBufferCount` is a simple Int type. Others, like the `addressableLeaseDuration` are more complex objects.

`ExternallyConfigured<T>` settings allow replacement of implementations of some classes, such as the Node Directory. They are settable from serialized JSON data in a configuration file. The configuration class must derive from ExternallyConfigured, where T is the interface this implementation will replace.

A truncated example of the EtcdNodeDirectory implementation of Node Directory:

```kotlin
class EtcdNodeDirectory(config: EtcdNodeDirectoryConfig, private val clock: Clock) : NodeDirectory {
    data class EtcdNodeDirectoryConfig(
        val url: String
    ) : ExternallyConfigured<NodeDirectory> {
        override val instanceType: Class<out NodeDirectory> = EtcdNodeDirectory::class.java
    }
    ... EtcdNodeDirectory implementation
}
```

## Configuration File

Orbit Server is set up with sensible default values for a simple, single node service. The easiest way to customize an Orbit Server is to use a configuration file. Orbit Server by default uses a `SettingsLoader` class which loads from a JSON-formatted configuration file. This file is searched for in 3 ways:

### ORBIT\_SETTINGS\_RAW environment variable

Orbit will first attempt to read a raw JSON data from an environment variable `ORBIT_SETTINGS_RAW`.

### ORBIT\_SETTINGS environment variable

Orbit will then attempt to load a configuration file found at the path specified in the `ORBIT_SETTINGS` environment variable, such as `/etc/orbit/orbit.json`.

### orbit.settings system property

Orbit will finally attempt to load a configuration file found at the path speciied in the 'orbit.settings\` system property.

For ExternallyConfigured classes, configuration takes the form of a serialized class to be loaded from Jackson ObjectMapper:

```javascript
    "nodeDirectory": [
        "orbit.server.etcd.EtcdNodeDirectory$EtcdNodeDirectoryConfig",
        {
            "url": "http://orbit-node-directory:2379"
        }
    ],
```


