A complete Consul client for MoonBit: agent, catalog, health, KV (with CAS, locks and semaphores), sessions, events, ACL, status, coordinate, prepared queries and config entries, with blocking queries and watch.
async fn main {
let client = @fetch.connect()
ignore(client.kv().put(pair))
let lock = @concurrency.Lock::new(client, "jobs/nightly")
lock.hold(() => run_the_job())
}| Package | Holds |
|---|---|
| moonbitstack/moonconsul | The API groups, Transport, Client::poll |
| moonbitstack/moonconsul/fetch | Fetch, connect |
| moonbitstack/moonconsul/concurrency | Lock, Semaphore, keep_alive, watch: what waits |
| moonbitstack/moonconsul/sd | Registry, moonsd's Registrar and Discovery on Consul |
| Method | Intent |
|---|---|
| service_register(reg, options~) | Register a service (with inline checks) on this agent |
| service_deregister(id, options~) | Deregister a service instance |
| check_register(reg, options~) | Register a check (optionally bound to a service) |
| check_deregister(check_id, options~) | Deregister a check |
| check_pass(check_id, options~) | Mark a TTL/HTTP/TCP/gRPC check passing |
| check_fail(check_id, options~) | Mark a check failing |
| check_update(update, options~) | Set a TTL check's status/output without resetting its clock |
| self(options~) | This agent's config, member record and stats |
| members(options~) | Cluster members this agent gossips with |
| members_with_filter(filter, options~) | Members, requiring a tag filter |
| join(address, wan~, options~) | Ask an agent to join the cluster (LAN or WAN) |
| leave(options~) | Leave the cluster gracefully |
| force_leave(node, options~) | Force a node out without its cooperation |
| enable_service_maintenance(service_id, reason~, options~) | Put a service instance in maintenance mode |
| disable_service_maintenance(service_id, options~) | Take a service instance out of maintenance mode |
| enable_node_maintenance(reason~, options~) | Put the whole node in maintenance mode |
| disable_node_maintenance(options~) | Take the node out of maintenance mode |
| update_acl_token(token, options~) | Replace the agent's local ACL token |
| Method | Intent |
|---|---|
| register(reg, options~) | Register a node/service/check against the catalog |
| deregister(dereg, options~) | Remove a node, service or check from the catalog |
| datacenters(options~) | Datacenters in the WAN federation |
| nodes(options~) | Nodes in this datacenter |
| node(node, options~) | One node and every service on it |
| services(options~) | Service names, each with its tag set |
| service(service, options~) | Instances of a service in this datacenter |
| Method | Intent |
|---|---|
| node(node, options~) | Checks on a node |
| checks(service, options~) | Checks belonging to a service |
| checks_in_state(state, options~) | Checks in a given state |
| service(service, passing~, options~) | Healthy instances of a service (blocking) |
| state(state, options~) | Checks in any of the three states |
| connect_service(service, passing~, options~) | Only connect-mesh-reachable instances |
| Method | Intent |
|---|---|
| get(key, options~) | Read one key (None when absent) |
| list(prefix, options~) | Every entry under a prefix |
| keys(prefix, options~) | Only the keys under a prefix |
| put(pair, options~) | Write a pair |
| delete(key, options~) | Delete a key |
| delete_cas(pair, options~) | Delete a key if its index still matches; true on success |
| delete_tree(prefix, options~) | Delete every entry under a prefix |
| cas(pair, options~) | Compare-and-swap; true on success |
| acquire(pair, options~) | Acquire the lock on a key for a session |
| release(pair, options~) | Release the lock held by a session |
| txn(ops, options~) | Atomic batch of read and write operations |
| Method | Intent |
|---|---|
| create(entry~, options~) | Create a session; the result carries the assigned id |
| destroy(id, options~) | Destroy a session, releasing everything it holds |
| renew(id, options~) | Renew a session; None if it expired |
| info(id, options~) | Read one session by id |
| node(node, options~) | Sessions active on a node |
| list(options~) | Every session in the datacenter |
| Method | Intent |
|---|---|
| fire(name, payload, options~, write_options~) | Fire an event, returning the accepted event |
| list(options~, query_options~) | List events, optionally by name |
| Method | Intent |
|---|---|
| leader(options~) | Address of the Raft leader (empty if none) |
| peers(options~) | Raft peer addresses of the cluster |
| Method | Intent |
|---|---|
| datacenters(options~) | Coordinates of every datacenter |
| nodes(options~) | Coordinates of the nodes in this datacenter |
| update(coord, options~) | Publish this node's own coordinate |
| Method | Intent |
|---|---|
| create(def, options~) | Create a query; result carries the assigned id |
| update(def, options~) | Update an existing query |
| get(id, options~) | Read a query by id |
| delete(id, options~) | Delete a query |
| execute(id_or_name, params~, options~) | Run a query by id or name |
| list(options~) | List every query in the datacenter |
| Method | Intent |
|---|---|
| get(kind, name, options~) | Read one config entry |
| list(kind, options~) | List the entries of one kind |
| set(entry, options~) | Write a config entry |
| delete(kind, name, options~) | Delete a config entry |
let lock = @concurrency.Lock::new(client, "jobs/nightly")
lock.hold(() => run_the_job())
let seats = @concurrency.Semaphore::new(client, "jobs/workers", 4)
seats.hold(() => run_a_worker())| Method | Does |
|---|---|
| hold(body) | Wait for it, run body with the session renewed, give it back. If it is lost, body is cancelled and this raises Conflict |
| acquire() | Wait for it. The session is renewed only during the wait, so a holder runs keep_alive itself |
| try_acquire() | Take it if it is free now |
| release() | Give it back, and destroy a session this value created |
| destroy() | Delete the keys of one nobody holds |
@concurrency.watch(client, Service("web", passing=true), (index, value) => {
println("\{index}: \{value.stringify()}")
})| Variant | Meaning |
|---|---|
| Transport(String) | The HTTP medium could not carry the request |
| Status(Int32, String) | Non-2xx agent response and its body |
| Json(String) | A response body was not the JSON expected |
| Conflict(String) | A lock or semaphore is held, in use, lost, or not one |
| NotFound | The key, session or entry does not exist |
| Param(String) | A bad argument before the call left the client |
pub(open) trait Transport {
async fn send(Self, Request) -> Response raise Refused
}moon clean && moon fmt && moon check --target all --deny-warn \
&& moon build --target all && moon test --target allpub(all) suberror Refused {
Transport(String)
Status(Int, String)
Json(String)
Conflict(String)
NotFound
Param(String)
}async fn ACL::auth_method_create(self : ACL, entry : ACLAuthMethod, options? : WriteOptions) -> (ACLAuthMethod, WriteMeta) raise Refusedasync fn ACL::auth_method_delete(self : ACL, name : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ACL::auth_method_list(self : ACL, options? : QueryOptions) -> (Array[ACLAuthMethod], QueryMeta) raise Refusedasync fn ACL::auth_method_read(self : ACL, name : String, options? : QueryOptions) -> (ACLAuthMethod, QueryMeta) raise Refusedasync fn ACL::auth_method_update(self : ACL, entry : ACLAuthMethod, options? : WriteOptions) -> (ACLAuthMethod, WriteMeta) raise Refusedasync fn ACL::binding_rule_create(self : ACL, rule : ACLBindingRule, options? : WriteOptions) -> (ACLBindingRule, WriteMeta) raise Refusedasync fn ACL::binding_rule_delete(self : ACL, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ACL::binding_rule_list(self : ACL, options? : QueryOptions) -> (Array[ACLBindingRule], QueryMeta) raise Refusedasync fn ACL::binding_rule_read(self : ACL, id : String, options? : QueryOptions) -> (ACLBindingRule, QueryMeta) raise Refusedasync fn ACL::binding_rule_update(self : ACL, rule : ACLBindingRule, options? : WriteOptions) -> (ACLBindingRule, WriteMeta) raise Refusedasync fn ACL::policy_delete(self : ACL, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ACL::role_delete(self : ACL, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ACL::token_delete(self : ACL, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ACL::token_login(self : ACL, params : ACLLoginParams, options? : WriteOptions) -> (ACLToken, WriteMeta) raise Refusedpub(all) struct ACLAuthMethod {
name : String?
kind : String?
description : String?
config : Map[String, String]?
ns : String?
partition : String?
}pub(all) struct ACLBindingRule {
id : String?
description : String?
auth_method : String?
selector : String?
bind_type : String?
bind_name : String?
ns : String?
partition : String?
}pub(all) struct ACLLoginParams {
auth_method : String?
bearer_token : String?
token_metadata : Map[String, String]?
}pub(all) struct ACLPolicy {
id : String?
name : String?
description : String?
rules : String?
datacenter : String?
ns : String?
partition : String?
hash : String?
}pub(all) struct ACLRole {
id : String?
name : String?
description : String?
policies : Array[ACLRolePolicyLink]?
ns : String?
partition : String?
hash : String?
}pub(all) struct ACLRolePolicyLink {
id : String?
name : String?
}pub(all) struct ACLToken {
id : String?
accessor_id : String?
secret_id : String?
description : String?
policies : Array[ACLTokenPolicyLink]?
roles : Array[ACLTokenRoleLink]?
is_local : Bool?
ns : String?
partition : String?
hash : String?
expiration_time : String?
}pub(all) struct ACLTokenPolicyLink {
id : String?
name : String?
}pub(all) struct ACLTokenRoleLink {
id : String?
name : String?
}async fn Agent::check_deregister(self : Agent, check_id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::check_fail(self : Agent, check_id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::check_pass(self : Agent, check_id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::check_register(self : Agent, reg : AgentCheckRegistration, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::check_update(self : Agent, update : AgentCheckUpdate, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::checks(self : Agent, options? : QueryOptions) -> (Map[String, HealthCheck], QueryMeta) raise Refusedasync fn Agent::disable_node_maintenance(self : Agent, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::disable_service_maintenance(self : Agent, service_id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::enable_node_maintenance(self : Agent, reason? : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::enable_service_maintenance(self : Agent, service_id : String, reason? : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::force_leave(self : Agent, node : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::join(self : Agent, address : String, wan? : Bool, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::members(self : Agent, options? : QueryOptions) -> (Array[AgentMember], QueryMeta) raise Refusedasync fn Agent::members_with_filter(self : Agent, filter : String, options? : QueryOptions) -> (Array[AgentMember], QueryMeta) raise Refusedasync fn Agent::service_deregister(self : Agent, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::service_register(self : Agent, reg : AgentServiceRegistration, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Agent::services(self : Agent, options? : QueryOptions) -> (Map[String, AgentService], QueryMeta) raise Refusedpub(all) struct AgentCheck {
id : String
name : String?
status : String?
notes : String?
output : String?
service_id : String?
service_name : String?
ns : String?
}pub(all) struct AgentCheckRegistration {
id : String?
name : String
notes : String?
service_id : String?
service_name : String?
ns : String?
status : String?
definition : AgentServiceCheck
}pub(all) struct AgentCheckUpdate {
check_id : String
status : String
output : String?
}pub(all) struct AgentMember {
name : String
addr : String
port : Int
tags : Map[String, String]?
status : String?
}pub(all) struct AgentService {
id : String
service : String
tags : Array[String]
address : String?
port : Int?
meta : Map[String, String]?
ns : String?
weights : AgentWeights?
}pub(all) struct AgentServiceCheck {
id : String?
name : String?
notes : String?
service_id : String?
status : String?
ttl : String?
interval : String?
timeout : String?
http : String?
tls_skip_verify : Bool?
http_method : String?
tcp : String?
grpc : String?
grpc_use_tls : Bool?
header : Map[String, Array[String]]?
deregister_critical_service_after : String?
alias_node : String?
alias_service : String?
success_before_passing : Int?
failures_before_critical : Int?
}pub(all) struct AgentServiceRegistration {
id : String?
name : String
tags : Array[String]?
address : String?
port : Int?
meta : Map[String, String]?
ns : String?
check : AgentServiceCheck?
checks : Array[AgentServiceCheck]?
enable_tag_override : Bool?
weights : AgentWeights?
}pub(all) struct AgentWeights {
passing : Int?
warning : Int?
}async fn Catalog::deregister(self : Catalog, dereg : CatalogDeregistration, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Catalog::node(self : Catalog, node : String, options? : QueryOptions) -> (CatalogNode, QueryMeta) raise Refusedasync fn Catalog::register(self : Catalog, reg : CatalogRegistration, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Catalog::service(self : Catalog, service : String, options? : QueryOptions) -> (Array[CatalogService], QueryMeta) raise Refusedpub(all) struct CatalogDeregistration {
node : String
address : String?
service_id : String?
check_id : String?
ns : String?
partition : String?
}pub(all) struct CatalogNodeService {
id : String
service : String
tags : Array[String]
meta : Map[String, String]?
ns : String?
port : Int?
address : String?
weights : AgentWeights?
}pub(all) struct CatalogRegistration {
node : String
address : String
node_meta : Map[String, String]?
ns : String?
partition : String?
service : CatalogService?
check : AgentCheck?
checks : Array[AgentCheck]?
}pub(all) struct CatalogService {
id : String
node : String
address : String
service : String
tags : Array[String]
meta : Map[String, String]?
ns : String?
partition : String?
port : Int?
weights : AgentWeights?
create_index : UInt64?
modify_index : UInt64?
}pub(all) struct Config {
address : String
scheme : String
datacenter : String?
ns : String?
token : String?
wait_time : Int64
consistency : ConsistencyMode
tls : TlsConfig
transport : &Transport?
}async fn ConfigEntries::delete(self : ConfigEntries, kind : String, name : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn ConfigEntries::get(self : ConfigEntries, kind : String, name : String, options? : QueryOptions) -> (ConfigEntry, QueryMeta) raise Refusedasync fn ConfigEntries::list(self : ConfigEntries, kind : String, options? : QueryOptions) -> (Array[ConfigEntry], QueryMeta) raise Refusedasync fn ConfigEntries::set(self : ConfigEntries, entry : ConfigEntry, options? : WriteOptions) -> WriteMeta raise Refusedpub(all) enum ConfigEntry {
ServiceDefault(ServiceDefaultConfigEntry)
ServiceRouter(ServiceRouterConfigEntry)
ServiceSplitter(ServiceSplitterConfigEntry)
ServiceResolver(ServiceResolverConfigEntry)
Mesh(MeshConfigEntry)
}pub(all) enum ConsistencyMode {
Default
Consistent
Stale
}async fn Coordinate::datacenters(self : Coordinate, options? : QueryOptions) -> (Array[CoordinateNode], QueryMeta) raise Refusedasync fn Coordinate::nodes(self : Coordinate, options? : QueryOptions) -> (Array[CoordinateEntry], QueryMeta) raise Refusedasync fn Coordinate::update(self : Coordinate, coord : CoordinateValue, options? : WriteOptions) -> WriteMeta raise Refusedpub(all) struct CoordinateValue {
vec : Array[Double]
error : Double
adjustment : Double
height : Double
}async fn Event::fire(self : Event, name : String, payload : Bytes, options? : EventFireOptions, write_options? : WriteOptions) -> (UserEvent, WriteMeta) raise Refusedasync fn Event::list(self : Event, options? : EventListOptions, query_options? : QueryOptions) -> (Array[UserEvent], QueryMeta) raise Refusedpub(all) struct EventFireOptions {
node_filter : String?
service_filter : String?
tag_filter : String?
}async fn Health::checks(self : Health, service : String, options? : QueryOptions) -> (Array[HealthCheck], QueryMeta) raise Refusedasync fn Health::checks_in_state(self : Health, state : String, options? : QueryOptions) -> (Array[HealthCheck], QueryMeta) raise Refusedasync fn Health::connect_service(self : Health, service : String, passing? : Bool, options? : QueryOptions) -> (Array[ServiceEntry], QueryMeta) raise Refusedasync fn Health::node(self : Health, node : String, options? : QueryOptions) -> (Array[HealthCheck], QueryMeta) raise Refusedasync fn Health::service(self : Health, service : String, passing? : Bool, options? : QueryOptions) -> (Array[ServiceEntry], QueryMeta) raise Refusedasync fn Health::state(self : Health, state : String, options? : QueryOptions) -> (Array[HealthCheck], QueryMeta) raise Refusedpub(all) struct HealthCheck {
node : String
check_id : String
name : String?
status : String?
notes : String?
output : String?
service_id : String?
service_name : String?
ns : String?
}pub(all) struct HealthService {
id : String
service : String
address : String?
tags : Array[String]
meta : Map[String, String]?
ns : String?
partition : String?
port : Int?
weights : AgentWeights?
}async fn KV::delete_tree(self : KV, prefix : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn KV::txn(self : KV, ops : Array[KVTxnOp], options? : QueryOptions) -> (KVTxnResponse, QueryMeta) raise Refusedpub(all) struct KVPair {
key : String
create_index : UInt64
modify_index : UInt64
lock_index : UInt64
flags : UInt64
value : Bytes
session : String?
}pub(all) struct KVTxnError {
op_index : Int
message : String
}pub(all) struct KVTxnOp {
verb : KVTxnOpVerb
key : String
value : Bytes?
index : UInt64?
session : String?
flags : UInt64?
}pub(all) enum KVTxnOpVerb {
Set
CAS
Delete
DeleteTree
DeleteCAS
Acquire
Release
Get
GetKeys
CheckSession
CheckIndex
CheckNotExists
Lock
Unlock
Read
}pub(all) struct MeshConfigEntry {
name : String
partition : String?
transparent_proxy : MeshTransparentProxy?
}pub(all) struct MeshTransparentProxy {
mode : String?
}async fn PreparedQuery::create(self : PreparedQuery, def : PreparedQueryDefinition, options? : WriteOptions) -> (String, WriteMeta) raise Refusedasync fn PreparedQuery::delete(self : PreparedQuery, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn PreparedQuery::execute(self : PreparedQuery, id_or_name : String, params? : PreparedQueryExecuteParams, options? : QueryOptions) -> (PreparedQueryExecuteResponse, QueryMeta) raise Refusedasync fn PreparedQuery::get(self : PreparedQuery, id : String, options? : QueryOptions) -> (Array[PreparedQueryDefinition], QueryMeta) raise Refusedasync fn PreparedQuery::list(self : PreparedQuery, options? : QueryOptions) -> (Array[PreparedQueryDefinition], QueryMeta) raise Refusedasync fn PreparedQuery::update(self : PreparedQuery, def : PreparedQueryDefinition, options? : WriteOptions) -> WriteMeta raise Refusedpub(all) struct PreparedQueryDefinition {
id : String?
name : String?
token : String?
ns : String?
partition : String?
service : ServiceQuery?
dns : DNSQuery?
}pub(all) struct PreparedQueryExecuteParams {
ns : String?
near : String?
limit : Int?
}pub(all) struct PreparedQueryExecuteResponse {
service : String?
datacenter : String?
nodes : Array[ServiceEntry]?
}pub(all) struct QueryMeta {
last_index : UInt64
last_hash : String?
last_contact : Int64
known_leader : Bool
request_time : Int64
}pub(all) struct QueryOptions {
datacenter : String?
ns : String?
token : String?
wait_index : UInt64?
wait_hash : String?
wait_time : Int64?
consistency : ConsistencyMode
near : String?
filter : String?
node_meta : Map[String, String]?
}pub(all) struct ServiceDefaultConfigEntry {
name : String
ns : String?
partition : String?
protocol : String?
mesh_gateway : ServiceMeshGateway?
}pub(all) struct ServiceMeshGateway {
mode : String?
}pub(all) struct ServiceQuery {
service : String
ns : String?
tags_any : Array[String]?
only_passing : Bool?
node_type : String?
failover : QueryDatacenterOptions?
}pub(all) struct ServiceResolverConfigEntry {
name : String
ns : String?
partition : String?
datacenter : String?
service : String?
failover : QueryDatacenterOptions?
redirect : String?
}pub(all) struct ServiceRouteDestination {
service : String?
ns : String?
}pub(all) struct ServiceRouteHTTPMatch {
path : String?
prefix : String?
regex : String?
}pub(all) struct ServiceRouterConfigEntry {
name : String
ns : String?
partition : String?
routes : Array[ServiceRoute]?
}pub(all) struct ServiceSplit {
weight : Double
service : String?
ns : String?
}pub(all) struct ServiceSplitterConfigEntry {
name : String
ns : String?
partition : String?
splits : Array[ServiceSplit]?
}async fn Session::create(self : Session, entry? : SessionEntry, options? : WriteOptions) -> (SessionEntry, WriteMeta) raise Refusedasync fn Session::destroy(self : Session, id : String, options? : WriteOptions) -> WriteMeta raise Refusedasync fn Session::info(self : Session, id : String, options? : QueryOptions) -> (SessionEntry?, QueryMeta) raise Refusedasync fn Session::list(self : Session, options? : QueryOptions) -> (Array[SessionEntry], QueryMeta) raise Refusedasync fn Session::node(self : Session, node : String, options? : QueryOptions) -> (Array[SessionEntry], QueryMeta) raise Refusedasync fn Session::renew(self : Session, id : String, options? : WriteOptions) -> (SessionEntry?, WriteMeta) raise Refusedpub(all) enum SessionBehavior {
Release
Delete
}pub(all) struct SessionEntry {
id : String?
name : String?
node : String?
checks : Array[String]?
lock_delay : Int64?
behavior : SessionBehavior?
ttl : String?
}async fn Status::leader(self : Status, options? : QueryOptions) -> (String, QueryMeta) raise Refusedpub(all) struct TlsConfig {
ca_file : String?
cert_file : String?
key_file : String?
insecure_skip_verify : Bool
}pub(all) struct UserEvent {
id : String
name : String
payload : Bytes?
node_filter : String?
service_filter : String?
tag_filter : String?
version : Int?
ltime : Int64?
}pub(all) enum WatchKind {
Key(String)
KeyPrefix(String)
Services
Nodes
Service(String, passing~ : Bool)
Checks(String)
State(String)
Event(String)
ConnectRoots
ConnectLeaf(String)
AgentService(String)
}pub(all) struct WriteMeta {
request_time : Int64
}pub(all) struct WriteOptions {
datacenter : String?
ns : String?
token : String?
}fn parse_u64(s : StringView) -> UInt64fn url_encode(s : String) -> StringInstall
Download zipA complete Consul client for MoonBit: agent, catalog, health, KV (with CAS, locks and semaphores), sessions, events, ACL, status, coordinate, prepared queries and config entries, with blocking queries and watch.