{"id":17246783,"url":"https://github.com/kuujo/vertigo","last_synced_at":"2025-04-13T18:40:27.461Z","repository":{"id":10170391,"uuid":"12254089","full_name":"kuujo/vertigo","owner":"kuujo","description":"Flow-based programming for the Vert.x application platform.","archived":false,"fork":false,"pushed_at":"2015-07-14T20:29:13.000Z","size":10085,"stargazers_count":155,"open_issues_count":19,"forks_count":24,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-03-27T09:21:31.652Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kuujo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-20T20:59:51.000Z","updated_at":"2024-05-21T16:09:37.000Z","dependencies_parsed_at":"2022-08-24T13:46:16.367Z","dependency_job_id":null,"html_url":"https://github.com/kuujo/vertigo","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kuujo%2Fvertigo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kuujo%2Fvertigo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kuujo%2Fvertigo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kuujo%2Fvertigo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kuujo","download_url":"https://codeload.github.com/kuujo/vertigo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248764174,"owners_count":21158038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T06:35:09.162Z","updated_at":"2025-04-13T18:40:27.422Z","avatar_url":"https://github.com/kuujo.png","language":"Java","funding_links":[],"categories":["大数据"],"sub_categories":["Spring Cloud框架"],"readme":"Vertigo [![Build Status](https://travis-ci.org/kuujo/vertigo.png)](https://travis-ci.org/kuujo/vertigo)\n=======\n\n#### Vertigo 0.7.0-RC2 has been released!\n*Vertigo 0.7.0 requires Vert.x 2.1*\n\n**Need support? Check out the [Vertigo Google Group][google-group]**\n\n**[Getting Started](#getting-started) | [Java User Manual](#java-user-manual) | [Javadoc](http://vertigo.kuujo.net/0.7.0/java)**\n\n[Javascript][vertigo-js] | [Python][vertigo-python]\n\nVertigo is a durable polyglot event processing framework built on the\n[Vert.x](http://vertx.io/) application platform. Combining concepts of cutting-edge\n[real-time systems](http://storm.incubator.apache.org/) and\n[flow-based programming](http://en.wikipedia.org/wiki/Flow-based_programming),\nVertigo allows real-time problems to be broken down into smaller tasks (as\nVert.x verticles) and distributed across a Vert.x cluster.\n\n* Manages multi-step event processing systems, from simple pipelines to\n  **complex networks of Vert.x modules/verticles**\n* Supports deployment of networks **within a single Vert.x instance or across a\n  Vert.x cluster** and provides automatic **failover** for failed components\n* **Coordinates startup and shutdown** of networks across the Vert.x cluster\n* **Promotes reusability** by abstracting communication details from verticle implementations,\n  allowing components to be arbitrarily connected to form complex networks\n* Guarantees **strong ordering** and **exactly-once** processing of messages\n* Handles **event bus flow control** and **automatic retries** on failures\n* Supports `Serializable` Java messages on the Vert.x event bus\n* Facilitates distribution of messages between multiple verticle instances using\n  **random, round-robin, mod hashing, fair, or fanout** methods\n* Provides **cluster-wide shared data** structures for synchronization\n* Supports **live network configuration changes** so networks do not have to\n  be shutdown in order to be reconfigured\n* Provides a simple **batch API** for efficiently batching messages between components\n* Support **command line deployment** of networks\n* Components can be written in **any Vert.x supported language**, with\n  APIs for Vertigo in [Javascript][vertigo-js] and [Python][vertigo-python]\n\nFor an in-depth explanation of how Vertigo works, see [how it works](#how-it-works)\n\n![YourKit](http://s13.postimg.org/nyb38p1ev/yklogo.png)\n\nYourKit is generously supporting Vertigo and other open-source projects with its\nfull-featured Java Profiler. Take a look at YourKit's leading software products:\n[YourKit Java Profiler](http://www.yourkit.com/java/profiler/index.jsp) and\n[YourKit .NET Profiler](http://www.yourkit.com/.net/profiler/index.jsp).\n\n# Java User Manual\n\n**Note: Vertigo 0.7.x requires Vert.x 2.1**\n\n1. [Getting Started](#getting-started)\n   * [Setup](#setup)\n      * [Adding Vertigo as a Maven dependency](#adding-vertigo-as-a-maven-dependency)\n      * [Including Vertigo in a Vert.x module](#including-vertigo-in-a-vertx-module)\n   * [Networks](#networks)\n   * [Components](#components)\n   * [The Vertigo cluster](#cluster)\n   * [A simple network](#a-simple-network)\n1. [Networks](#networks-1)\n   * [Creating a new network](#creating-a-new-network)\n   * [Adding components to a network](#adding-components-to-a-network)\n   * [Creating connections between components](#)\n   * [Routing messages between multiple component instances](#routing-messages-between-multiple-component-instances)\n   * [Creating networks from JSON](#creating-networks-from-json)\n1. [Components](#components-1)\n   * [Creating a component](#creating-a-component)\n   * [The elements of a Vertigo component](#the-elements-of-a-vertigo-component)\n1. [Messaging](#messaging)\n   * [Sending messages on an output port](#sending-messages-on-an-output-port)\n   * [Receiving messages on an input port](#receiving-messages-on-an-input-port)\n   * [Working with message groups](#working-with-message-groups)\n   * [Working with message batches](#working-with-message-batches)\n   * [Providing serializable messages](#providing-serializable-messages)\n   * [Sendinging and receiving files](#sending-and-receiving-files)\n1. [Network Deployment and Clustering](#network-deployment-and-clustering)\n   * [Starting a cluster from the command line](#starting-a-cluster-from-the-command-line)\n   * [Starting a cluster programmatically](#starting-a-cluster-programmatically)\n   * [Referencing a cluster programmatically](#referencing-a-cluster-programmatically)\n   * [Accessing a cluster through the event bus](#accessing-a-cluster-through-the-event-bus)\n   * [Deploying a network](#deploying-a-network)\n   * [Deploying a network from json](#deploying-a-network-from-json)\n   * [Undeploying a network](#undeploying-a-network)\n   * [Checking if a network is deployed](#checking-if-a-network-is-deployed)\n   * [Listing networks running in a cluster](#listing-networks-running-in-a-cluster)\n   * [Deploying a bare network](#deploying-a-bare-network)\n   * [Reconfiguring a network](#reconfiguring-a-network)\n   * [Working with active networks](#working-with-active-networks)\n   * [Deploying a network from the command line](#deploying-a-network-from-the-command-line)\n1. [Cluster Management](#cluster-management)\n   * [Accessing the cluster from within a component](#accessing-the-cluster-from-within-a-component)\n   * [Deploying modules and verticles to the cluster](#deploying-modules-and-verticles-to-the-cluster)\n   * [Undeploying modules and verticles from the cluster](#undeploying-modules-and-verticles-from-the-cluster)\n   * [Working with cluster groups](#working-with-cluster-groups)\n1. [Cluster-wide Shared Data](#cluster-wide-shared-data)\n   * [AsyncMap](#asyncmap)\n   * [AsyncSet](#asyncset)\n   * [AsyncList](#asynclist)\n   * [AsyncQueue](#asyncqueue)\n   * [AsyncCounter](#asynccounter)\n   * [Accessing shared data over the event bus](#accessing-shared-data-over-the-event-bus)\n1. [Hooks](#hooks)\n   * [InputHook](#inputhook)\n   * [OutputHook](#outputhook)\n   * [IOHook](#iohook)\n   * [ComponentHook](#componenthook)\n1. [Logging](#logging)\n   * [Logging messages to output ports](#logging-messages-to-output-ports)\n   * [Reading log messages](#reading-log-messages)\n1. [How it works](#how-it-works)\n   * [Configurations](#configurations)\n   * [Cluster](#cluster)\n   * [Networks](#networks-2)\n   * [Components](#components-2)\n   * [Communication](#communication)\n\n# Getting Started\nThis is a brief tutorial that will help guide you through high-level Vertigo\nconcepts and go through a simple network example. Check out the repository\nfor more [examples](https://github.com/kuujo/vertigo/tree/master/examples).\n\n## Setup\nVertigo can be added to your project as a Maven dependency or included in\nyour modules via the Vert.x module system.\n\n### Adding Vertigo as a Maven dependency\n\n```\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.kuujo\u003c/groupId\u003e\n  \u003cartifactId\u003evertigo\u003c/artifactId\u003e\n  \u003cversion\u003e0.7.0-RC2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.kuujo\u003c/groupId\u003e\n  \u003cartifactId\u003evertigo-util\u003c/artifactId\u003e\n  \u003cversion\u003e0.7.0-RC2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Including Vertigo in a Vert.x module\n\nTo use the Vertigo Java API, you can include the Vertigo module in your module's\n`mod.json` file. This will make Vertigo classes available within your module.\n\n```\n{\n  \"main\": \"com.mycompany.myproject.MyVerticle\",\n  \"includes\": \"net.kuujo~vertigo~0.7.0-RC2\"\n}\n```\n\nYou can also include the Vertigo utilities module which provides additional Java\nhelpers for operating on Vertigo streams.\n\n```\n{\n  \"includes\": \"net.kuujo~vertigo-util~0.7.0-RC2\"\n}\n```\n\n## Networks\nNetworks are collections of Vert.x verticles and modules that are connected\ntogether by input and output ports. Each component in a network contains processing\nlogic, and connections between components indicate how messages should be\npassed between them. Networks can be created either in code or in JSON and can\nbe deployed in code or from the command line.\n\n![Vertigo network](http://s21.postimg.org/ve93v28bb/Untitled_Diagram.png)\n\n## Components\n\nAs with any Vert.x verticle, Vertigo components can be deployed with any number\nof instances. Components communicate with each other over the Vert.x event bus.\nBut Vertigo doesn't use raw event bus addresses. Instead, components communicate\nthrough named output and input ports. This allows components to be abstracted\nfrom the relationships between them, making them reusable.\n\nMessaging in Vertigo is inherently uni-directional. Components receive messages\nfrom other components on input ports and send messages to other components on\noutput ports.\n\n![Direct connections](http://s21.postimg.org/65oa1e3dj/Untitled_Diagram_1.png)\n\nMessages are not routed through any central router. Rather, components\ncommunicate with each other directly over the event bus.\n\n```java\npublic class MyComponent extends ComponentVerticle {\n\n  @Override\n  public void start() {\n    input.port(\"in\").messageHandler(new Handler\u003cString\u003e() {\n      public void handle(String message) {\n        output.port(\"out\").send(message);\n      }\n    });\n  }\n\n}\n```\n\nPorts do not have to be explicitly declared. Vertigo will lazily create ports\nif they don't already exist. Messages can be of any type that is supported by the\nVert.x event bus. Vertigo guarantees that messages will always arrive in the order\nin which they were sent.\n\nIn cases where a connection connects two components with multiple instances,\nVertigo facilitates special routing between the components with *selectors*.\n\n![Selectors](http://s21.postimg.org/a3bjqsq6v/Untitled_Diagram_2.png)\n\nWhile components receive messages on input ports and send messages to output ports,\nthe network configuration is used to define how ports on different components\nrelate to one another. Connections between components/ports in your network indicate\nhow messages will flow through the network.\n\n```java\nNetworkConfig network = vertigo.createNetwork(\"foo\");\nnetwork.addComponent(\"bar\", \"bar.js\", 2);\nnetwork.addComponent(\"baz\", \"baz.py\", 4);\nnetwork.createConnection(\"bar\", \"out\", \"baz\", \"in\");\n```\n\n## The Vertigo Cluster\nVertigo provides its own cluster abstraction within the Vert.x cluster. Vertigo\nclusters are simple collections of verticles that manage deployment of networks,\nallow modules and verticles to be deploy remotely (over the event bus)\nand provide cluster-wide shared data structures. Clusters can be run either in\na single Vert.x instance (for testing) or across a Vert.x cluster.\n\n![Cluster](http://s8.postimg.org/n535zhv9h/cluster.png)\n\nRather than communicating over the unreliable event bus, Vertigo uses Hazelcast\ndata structures to coordinate between the cluster and components.\nThis is one of the properties that makes Vertigo networks fault-tolerant. Even if\na failure occurs, the network configuration will remain in the cluster and Vertigo\nwill automatically failover any failed components.\n\n## A Simple Network\nVertigo provides all its API functionality through a single `Vertigo` object.\n\n```java\nVertigo vertigo = new Vertigo(this);\n```\n\nThe `Vertigo` object supports creating and deploying networks. Each language\nbinding has an equivalent API.\n\n```java\nNetworkConfig network = vertigo.createNetwork(\"word-count\");\nnetwork.addComponent(\"word-feeder\", RandomWordCounter.class.getName());\nnetwork.addComponent(\"word-counter\", WordCounter.class.getName(), 2);\nnetwork.createConnection(\"word-feeder\", \"word\", \"word-counter\", \"word\", new HashSelector());\n```\n\nVertigo components can be implemented in a variety of languages since they're\njust Vert.x verticles. This network contains two components. The first component\nis a Python component that will feed random words to its `word` out port. The second\ncomponent is a Javascript component that will count words received on its `word` in\nport. The network therefore defines a connection between the `word-feeder` component's\n`word` out port and the `word-counter` component's `word` in port.\n\nNote that since we defined two instances of the `word-counter` component, it's\nimportant that the same words always go to the same instance, so we use a\n`HashSelector` on the connection to ensure the same word always goes to the\nsame component instance.\n\n`random_word_feeder.py`\n\n```python\nimport vertx\nfrom vertigo import component, input\n\n@component.start_handler\ndef start_handler(error=None):\n  if not error:\n    words = ['apple', 'banana', 'pear']\n    def feed_random_word(timer_id):\n      output.send('word', words[rand(len(words)-1)])\n    vertx.set_periodic(1000, feed_random_word)\n```\n\nHere we simply send a random word to the `word` out port every second.\n\n`word_counter.js`\n\n```javascript\nvar input = require('vertigo/input');\nvar output = require('vertigo/output');\n\nvar words = {};\ninput.port('word').messageHandler(function(word) {\n  if (words[word] === undefined) {\n    words[word] = 0;\n  }\n  words[word]++;\n  output.port('count').send({word: word, count: words[word]});\n});\n```\n\nThis component registers a message handler on the `word` in port, updates\nan internal count for the word, and sends the updated word count on the\n`count` out port.\n\nIn order for a network to be deployed, one or more nodes of a Vertigo cluster\nmust be running in the Vert.x cluster. Vertigo clusters are made up of simple\nVert.x verticles. To deploy a cluster node deploy the `vertigo-cluster` module.\n\n```\nvertx runmod net.kuujo~vertigo-cluster~0.7.0-RC2 -conf cluster.json\n```\n\nThe cluster configuration requires a `cluster` name.\n\n```\n{\n  \"cluster\": \"test-cluster\"\n}\n```\n\nA test cluster can also be deployed locally through the `Vertigo` API.\n\n```java\nvertigo.deployCluster(\"test-cluster\", new Handler\u003cAsyncResult\u003cCluster\u003e\u003e() {\n  public void handle(AsyncResult\u003cCluster\u003e result) {\n    Cluster cluster = result.result();\n  }\n});\n```\n\nOnce the cluster has been deployed we can deploy a network to the cluster.\n\n```java\ncluster.deployNetwork(network);\n```\n\nVertigo also supports deploying networks from the command line using simple\nJSON configuration files.\nSee [deploying a network from the command line](#deploying-a-network-from-the-command-line)\n\n## Networks\nVertigo networks are collections of Vert.x verticles and modules that are connected\ntogether by the Vert.x event bus. Networks and the relationships therein are defined\nexternally to their components, promoting reusability.\n\nEach Vertigo network must have a unique name within the Vert.x cluster in which it\nis deployed. Vertigo uses the network name to coordinate deployments and configuration\nchanges for the network.\n\nNetworks are made up of any number of components which can be arbitrarily connected\nby input and output ports. A Vertigo component is simple a Vert.x module or verticle,\nand can thus have any number of instances associated with it.\n\n### Creating a network\nTo create a new network, create a new `Vertigo` instance and call the `createNetwork` method.\n\n```java\nVertigo vertigo = new Vertigo(this);\nNetworkConfig network = vertigo.createNetwork(\"my-network\");\n```\n\nAll Vertigo networks have an explicit, unique name. This name is very important to\nVertigo as it can be used to reference networks from anywhere within a Vert.x cluster,\nbut more on that later.\n\n### Adding components to a network\nTo add a component to the network, use one of the `addVerticle` or `addModule` methods.\n\n```java\nnetwork.addVerticle(\"foo\", \"foo.js\");\n```\n\nThe `addVerticle` and `addModule` methods have the following signatures:\n\n* `addModule(String name, String moduleName)`\n* `addModule(String name, String moduleName, JsonObject config)`\n* `addModule(String name, String moduleName, int instances)`\n* `addModule(String name, String moduleName, JsonObject config, int instances)`\n* `addVerticle(String name, String main)`\n* `addVerticle(String name, String main, JsonObject config)`\n* `addVerticle(String name, String main, int instances)`\n* `addVerticle(String name, String main, JsonObject config, int instances)`\n\nJust as with networks, Vertigo components are explicitly named. The component name\n*must be unique within the network to which the component belongs*.\n\n```java\nNetworkConfig network = vertigo.createNetwork(\"test\");\nnetwork.addVerticle(\"foo\", \"foo.js\", 2);\nnetwork.addModule(\"bar\", \"com.bar~bar~1.0\", 4);\n```\n\nThe `NetworkConfig` API also exposes an abstract `addComponent` method which detects\nwhether the added component is a module or a verticle based on module naming conventions.\n\n* `addComponent(String name, String moduleOrMain)`\n* `addComponent(String name, String moduleOrMain, JsonObject config)`\n* `addComponent(String name, String moduleOrMain, int instances)`\n* `addComponent(String name, String moduleOrMain, JsonObject config, int instances)`\n\n```java\nnetwork.addComponent(\"foo\", \"foo.js\", 2); // Adds a verticle component.\nnetwork.addComponent(\"bar\", \"com.bar~bar~1.0\", 4); // Adds a module component.\n```\n\nOnce a component has been added to the network, the component configuration will\nbe returned. Users can set additional options on the component configuration. The\nmost important of these options is the `group` option. When deploying networks within\na Vert.x cluster, the `group` indicates the HA group to which to deploy the module or\nverticle.\n\n### Creating connections between components\nA set of components is not a network until connections are created between those\ncomponents. Vertigo uses a concept of *ports* to abstract input and output from\neach component instance. When creating connections between components, you must\nspecify a component and port to which the connection connects. Each connection\nbinds one component's output port with another component's input port.\n\nTo create a connection between two components use the `createConnection` method.\n\n```java\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\");\n```\n\nThe arguments to the `createConnection` method are, in order:\n* The source component's name\n* The source component's output port to connect\n* The target component's name\n* The target component's input port to connect\n\nYou may wonder why components and ports are specified by strings rather than\nobjects. Vertigo supports reconfiguring live networks with partial configurations,\nso objects may not necessarily be available within the network configuration\nwhen a partial configuration is created. More on partial network deployment\nand runtime configuration changes in the [deployment](#deployment) section.\n\n### Routing messages between multiple component instances\nJust as with Vert.x verticles and modules, each Vertigo component can support\nany number of instances. But connections are created between components and\nnot component instances. This means that a single connection can reference\nmultiple instances of each component. By default, the Vert.x event bus routes\nmessages to event bus handlers in a round-robin fashion. But Vertigo provides\nadditional routing methods known as *selectors*. Selectors indicate how messages\nshould be routed between multiple instances of a component.\n\n![Selectors](http://s21.postimg.org/a3bjqsq6v/Untitled_Diagram_2.png)\n\nVertigo provides several selector types by default and supports custom selectors\nas well.\n\n* Round robin selector - selects targets in a round-robin fashion\n* Random selector - selects a random target to which to send each message\n* Hash selector - uses a simple mod hash algorithm to select a target for each message\n* Fair selector - selects the target with the least number of messages in its send queue\n* All selector - sends each message to all target instances\n* Custom selector - user provided custom selector implementation\n\nThe `ConnectionConfig` API provides several methods for setting selectors\non a connection.\n* `roundSelect()` - sets a round-robin selector on the connection\n* `randomSelect()` - sets a random selector on the connection\n* `hashSelect()` - sets a mod hash based selector on the connection\n* `fairSelect()` - sets a fair selector on the connection\n* `allSelect()` - sets an all selector on the connection\n* `customSelect(Selector selector)` - sets a custom selector on the connection\n\n### Creating networks from JSON\nVertigo supports creating networks from json configurations. To create a network\nfrom json call the `Vertigo.createNetwork(JsonObject)` method.\n\n```java\nJsonObject json = new JsonObject().putString(\"name\", \"test-network\");\nvertigo.createNetwork(json);\n```\n\nThe JSON configuration format is as follows:\n\n* `name` - the network name\n* `cluster` - the cluster to which to deploy the network. This option applies\n  only when deploying the network from the command line\n* `components` - an object of network components, keyed by component names\n   * `name` - the component name\n   * `type` - the component type, either `module` or `verticle`\n   * `main` - the verticle main (if the component is a verticle)\n   * `module` - the module name (if the component is a module)\n   * `config` - the module or verticle configuration\n   * `instances` - the number of component instances\n   * `group` - the component deployment group (Vert.x HA group for clustering)\n* `connections` - an array of network connections\n   * `source` - an object defining the connection source\n      * `component` - the source component name\n      * `port` - the source component's output port\n   * `target` - an object defining the connection target\n      * `component` - the target component name\n      * `port` - the target component's input port\n   * `selector`- an object defining the connection selector\n      * `type` - the selector type, e.g. `round-robin`, `random`, `hash`, `fair`, `all`, or `custom`\n      * `selector` - for custom selectors, the selector class\n      * `...` - additional selector options\n\nFor example...\n\n```\n{\n  \"name\": \"my-network\",\n  \"cluster\": \"test-cluster\",\n  \"components\": {\n    \"foo\": {\n      \"name\": \"foo\",\n      \"type\": \"verticle\",\n      \"main\": \"foo.js\",\n      \"config\": {\n        \"foo\": \"bar\"\n      },\n      \"instances\": 2\n    },\n    \"bar\": {\n      \"name\": \"bar\",\n      \"type\": \"module\",\n      \"module\": \"com.foo~bar~1.0\",\n      \"instances\": 4\n    }\n  },\n  \"connections\": [\n    {\n      \"source\": {\n        \"component\": \"foo\",\n        \"port\": \"out\"\n      },\n      \"target\": {\n        \"component\": \"bar\",\n        \"port\": \"in\"\n      },\n      \"selector\": {\n        \"type\": \"fair\"\n      }\n    }\n  ]\n}\n```\n\nJSON network configurations can be used to deploy Vertigo networks from the command\nline using the `vertx` command line tool. For more information see\n[deploying networks from the command line](#deploying-networks-from-the-command-line)\n\n## Components\nNetworks are made up of any number of *components* which are simply Vert.x verticles or\nmodules that are connected together according to the network configuration. Each component\nis a \"black box\" that receives input on named input ports and sends output to named output\nports. By their nature, components do not know from where they received messages or to where\nthey're sending messages.\n\n### Creating a component\nTo create a Java component, extend the base `ComponentVerticle` class.\n\n```java\npublic class MyComponent extends ComponentVerticle {\n\n  @Override\n  public void start() {\n  \n  }\n\n}\n```\n\nThe `ComponentVerticle` base class is simply a special extension of the Vert.x `Verticle`\nthat synchronizes with other components in the network at startup and provides Vertigo\nspecific APIs. Once the component has completed startup it will call the `start()` method\njust like any other verticle.\n\n### The elements of a Vertigo component\nThe `ComponentVerticle` base class provides the following additional `protected` fields:\n* `vertigo` - a `Vertigo` instance\n* `cluster` - the Vertigo `Cluster` to which the component belongs\n* `input` - the component's `InputCollector`, an interface to input ports\n* `output`- the component's `OutputCollector`, an interface to output ports\n* `logger` - the component's `PortLogger`, a special logger that logs messages to output ports\n\nThe most important of these variables is the `input` and `output` objects on which messages\nare received and sent respectively. In Vertigo, messages flow in only one direction, so\nmessages can only be received on input ports and sent to output ports.\n\n## Messaging\nThe Vertigo messaging API is simply a wrapper around the Vert.x event bus.\nVertigo messages are not sent through any central router. Rather, Vertigo uses\nnetwork configurations to create direct event bus connections between components.\nVertigo components send and receive messages using only output and input *ports*\nand are hidden from event bus address details which are defined in network configurations.\nThis is the element that makes Vertigo components reusable.\n\nRather than routing messages through a central router, components communicate\ndirectly with one another over the event bus, ensuring optimal performance.\n\n![Direct connections](http://s21.postimg.org/65oa1e3dj/Untitled_Diagram_1.png)\n\nVertigo messages are guaranteed to arrive *in the order in which they were sent*\nand to only be processed *exactly once*. Vertigo also provides an API\nthat allows for logical grouping and ordering of collections of messages known as\n[groups](#working-with-message-groups). Groups are strongly ordered named batches\nof messages that can be nested.\n\nFor more information on messaging see [how Vertigo handles messaging](#how-vertigo-handles-messaging)\n\n### Sending messages on an output port\nTo reference an output port, use the `output.port(String name)` method.\n\n```java\nOutputPort port = output.port(\"out\");\n```\n\nIf the referenced output port is not defined in the network configuration, the\nport will be lazily created, though it will not actually reference any connections.\n\nAny message that can be sent on the Vert.x event bus can be sent on the output port.\nTo send a message on the event bus, simply call the `send` method.\n\n```java\noutput.port(\"out\").send(\"Hello world!\");\n```\n\nInternally, Vertigo will route the message to any connections as defined in the\nnetwork configuration.\n\nOutput ports also support custom message serialization.\nSee [providing serializable messages](#providing-serializable-messages)\n\n### Receiving messages on an input port\nInput ports are referenced in the same was as output ports.\n\n```java\nInputPort port = input.port(\"in\");\n```\n\nTo receive messages on an input port, register a message handler on the port.\n\n```java\ninput.port(\"in\").messageHandler(new Handler\u003cString\u003e() {\n  public void handle(String message) {\n    output.port(\"out\").send(message);\n  }\n});\n```\n\nNote that Vertigo messages arrive in plain format and not in any sort of `Message`\nwrapper. This is because Vertigo messages are inherently uni-directional, and message\nacking is handled internally.\n\n### Working with message groups\nVertigo provides a mechanism for logically grouping messages appropriately\nnamed *groups*. Groups are named logical collections of messages that are strongly\nordered by name. Before any given group can stat, each of the groups of the same\nname at the same level that preceded it must have been completed. Additionally,\nmessages within a group are *guaranteed to be delivered to the same instance* of each\ntarget component. In other words, routing is performed per-group rather than per-message.\n\n![Groups](http://s30.postimg.org/655svvk3l/groups.png)\n\nFor an interesting example of groups see the [FileSender](https://github.com/kuujo/vertigo/blob/master/util/src/main/java/net/kuujo/vertigo/io/FileSender.java)\nand [FileReceiver](https://github.com/kuujo/vertigo/blob/master/util/src/main/java/net/kuujo/vertigo/io/FileReceiver.java) utilities.\n\nWhen a new output group is created, Vertigo will await the completion of all groups\nof the same name that were created prior to the new group before sending the new group's\nmessages.\n\n```java\noutput.port(\"out\").group(\"foo\", new Handler\u003cOutputGroup\u003e() {\n  public void handle(OutputGroup group) {\n    group.send(\"foo\").send(\"bar\").send(\"baz\").end();\n  }\n});\n```\n\nThe `group` method can also accept an arbitrary `Serializable` object as the second\nargument. This argument will be passed to the input group's `startHandler` as you'll see\nbelow and can be used to initialize the group.\n\n```java\noutput.port(\"out\").group(\"foo\", new JsonObject().putString(\"bar\", \"baz\"), new Handler\u003cOutputGroup\u003e() {\n  public void handle(OutputGroup group) {\n    group.send(\"foo\").send(\"bar\").send(\"baz\").end();\n  }\n});\n```\n\nNote that the group's `end()` method *must* be called in order to indicate completion of\nthe group. *Groups are fully asynchronous*, meaning they support asynchronous calls to other\nAPIs, and this step is crucial to that functionality.\n\n```java\noutput.port(\"out\").group(\"foo\", new Handler\u003cOutputGroup\u003e() {\n  public void handle(final OutputGroup group) {\n    someObject.someAsyncApi(new Handler\u003cAsyncResult\u003cString\u003e\u003e() {\n      public void handle(AsyncResult\u003cString\u003e result) {\n        if (result.succeeded()) {\n          group.send(result.result()).end();\n        }\n      }\n    });\n  }\n});\n```\n\nThe group's `end()` method can also accept an arbitrary `Serializable` object that will\nbe passed to the input group's `endHandler`.\n\n```java\ngroup.end(new JsonObject().putString(\"foo\", \"bar\"));\n```\n\nThe `OutputGroup` API exposes the same methods as the `OutputPort`. That means that groups\ncan be nested and Vertigo will still guarantee ordering across groups.\n\n```java\noutput.port(\"out\").group(\"foo\", new Handler\u003cOutputGroup\u003e() {\n  public void handle(OutputGroup group) {\n    group.group(\"bar\", new Handler\u003cOutputGroup\u003e() {\n      public void handle(OutputGroup group) {\n        group.send(1).send(2).send(3).end();\n      }\n    });\n    group.group(\"baz\", new Handler\u003cOutputGroup\u003e() {\n      public void handle(OutputGroup group) {\n        group.send(4).send(5).send(6).end();\n      }\n    });\n    // Since two child groups were created, this group will not be ended\n    // until both children have been ended.\n    group.end();\n  }\n});\n```\n\nAs with receiving messages, to receive message groups register a handler on an\ninput port using the `groupHandler` method, passing a group name as the first\nargument.\n\n```java\ninput.port(\"in\").groupHandler(\"foo\", new Handler\u003cInputGroup\u003e() {\n  public void handle(InputGroup group) {\n    group.messageHandler(new Handler\u003cString\u003e() {\n      public void handle(String message) {\n        output.port(\"out\").send(message);\n      }\n    });\n  }\n});\n```\n\nThe `InputGroup` API also supports a `startHandler` and `endHandler`. The `endHandler`\ncan be particularly useful for aggregations. Vertigo guarantees that if a group's\n`endHandler` is called then *all* of the messages sent for that group were received\nby that group.\n\n```java\ninput.port(\"in\").groupHandler(\"foo\", new Handler\u003cInputGroup\u003e() {\n  public void handle(InputGroup group) {\n\n    final Set\u003cString\u003e messages = new HashSet\u003c\u003e();\n\n    group.messageHandler(new Handler\u003cString\u003e() {\n      public void handle(String message) {\n        messages.add(message);\n      }\n    });\n\n    group.endHandler(new Handler\u003cVoid\u003e() {\n      public void handle(Void ignore) {\n        System.out.println(\"Received \" + messages.size() + \" messages in group.\");\n      }\n    });\n  }\n});\n```\n\nDepending on how the group is formed, the group's `startHandler` and `endHandler`\ncan each accept arbitrary `Serializable` objects. This can be useful for initialization\nand cleanup.\n\n```java\ngroup.startHandler(new Handler\u003cJsonObject\u003e() {\n  public void handle(JsonObject args) {\n    String filename = args.getString(\"filename\");\n  }\n});\n```\n\nGroup handlers are called in the following manner:\n* When an input group is created, the `groupHandler` will be called\n* When input group initialization arguments are received, the `startHandler` will be called.\n  This will always occur before any messages have been received by the group.\n* Once the group's `messageHandler` has been set, the `messageHandler` will begin\n  receiving messages. No messages will be received until a message handler is registered,\n  so asynchronous APIs can be called without losing messages\n* Once all messages in the group have been received and/or all child groups have completed\n  (there own `endHandler` has been called) the group's `endHandler` will be called.\n\nAs with output groups, input groups can be nested, representing the same structure\nsent by an output group.\n\n```java\ninput.port(\"in\").groupHandler(\"foo\", new Handler\u003cInputGroup\u003e() {\n  public void handle(InputGroup group) {\n    group.group(\"bar\", new Handler\u003cInputGroup\u003e() {\n      public void handle(InputGroup group) {\n        group.messageHandler(new Handler\u003cInteger\u003e() {\n          public void handle(Integer number) {\n            output.port(\"bar\").send(number);\n          }\n        });\n      }\n    });\n    group.group(\"baz\", new Handler\u003cInputGroup\u003e() {\n      public void handle(InputGroup group) {\n        group.messageHandler(new Handler\u003cString\u003e() {\n          public void handle(String string) {\n            output.port(\"baz\").send(string);\n          }\n        });\n      }\n    });\n  }\n});\n```\n\n### Working with message batches\nBatches are similar to groups in that they represent collections of messages.\nBatches even use a similar API to groups. However, batches differ from groups\nin that they represent collections of output to all connections. In other words,\nwhereas groups are guaranteed to always be delivered to the same target component\ninstance, batches use normal selection routines to route each individual message.\nAdditionally, batches cannot be nested like groups, but groups can be contained\nwithin batches. Batches simply represent windows of output from a port.\n\n![Batches](http://s30.postimg.org/dwmiufo8x/groups_1.png)\n\nThe batch API works similarly to the group API, but batches are *not* named.\n```java\noutput.port(\"out\").batch(new Handler\u003cOutputBatch\u003e() {\n  public void handle(OutputBatch batch) {\n    batch.send(\"foo\").send(\"bar\").send(\"baz\").end();\n  }\n});\n```\n\nJust as with groups, batches need to be explicitly ended. However, only one batch\ncan be open for any given connection at any given time, so that means that a new\nbatch will not open until the previous batch has been ended.\n\nThe `batch` method can also accept an arbitrary `Serializable` object that will\nbe passed to the input batch's `startHandler`. This can be useful for initialization.\n\nSimilarly, the batch's `end` method can accept an arbitrary object.\n\n```java\noutput.port(\"out\").batch(new JsonObject().putString(\"foo\", \"bar\"), new Handler\u003cOutputBatch\u003e() {\n  public void handle(OutputBatch batch) {\n    batch.end(new JsonObject().putString(\"bar\", \"baz\"));\n  }\n});\n```\n\nOn the input port side, the batch API works similarly to the group API.\n\n```java\ninput.port(\"in\").batchHandler(new Handler\u003cInputBatch\u003e() {\n  public void handle(InputBatch batch) {\n\n    // Aggregate all messages from the batch.\n    final JsonArray messages = new JsonArray();\n    batch.messageHandler(new Handler\u003cString\u003e() {\n      public void handle(String message) {\n        messages.add(message);\n      }\n    });\n\n    // Send the aggregated array once the batch is ended.\n    batch.endHandler(new Handler\u003cVoid\u003e() {\n      public void handle(Void event) {\n        output.port(\"out\").send(messages);\n      }\n    });\n  }\n});\n```\n\nThe batch's `startHandler` and `endHandler` can each be called with an arbitrary\nobject that is defined by the sender. So, your batch may expect a `String` file\nname during initialization for example:\n\n```java\nbatch.startHandler(new Handler\u003cString\u003e() {\n  public void handle(String fileName) {\n    File file = new File(fileName);\n  }\n});\n```\n\nBatches cannot be nested, but they can contain groups.\n```java\noutput.port(\"out\").batch(new Handler\u003cOutputBatch\u003e() {\n  public void handle(OutputBatch batch) {\n    batch.group(\"fruits\", new Handler\u003cOutputGroup\u003e() {\n      public void handle(OutputGroup group) {\n        group.send(\"apple\").send(\"banana\").send(\"peach\").end();\n      }\n    });\n    batch.end();\n  }\n});\n```\n\nEven if a batch is ended, it will not internally end and allow the next batch to\nbe created until any child groups have been successfully ended.\n\nBatch handlers are called in the following manner:\n* When an input batch is created, the `batchHandler` will be called\n* When input batch initialization arguments are received, the `startHandler` will be called.\n  This will always occur before any messages have been received in the batch.\n* Once the batch's `messageHandler` has been set, the `messageHandler` will begin\n  receiving messages. No messages will be received until a message handler is registered,\n  so asynchronous APIs can be called without losing messages\n* Once all messages in the batch have been received and/or all child groups have completed\n  (there own `endHandler` has been called) the batch's `endHandler` will be called.\n\nGroups within batches can be received in the same manner as they are with groups.\n\n```java\ninput.port(\"in\").batchHandler(new Handler\u003cInputBatch\u003e() {\n  public void handle(InputBatch batch) {\n\n    batch.groupHandler(\"fruits\", new Handler\u003cInputGroup\u003e() {\n      public void handle(InputGroup group) {\n\n        final Set\u003cString\u003e fruits = new HashSet\u003c\u003e();\n        group.messageHandler(new Handler\u003cString\u003e() {\n          public void handle(String message) {\n            fruits.add(message);\n          }\n        });\n\n        group.endHandler(new Handler\u003cVoid\u003e() {\n          public void handle(Void event) {\n            System.out.println(\"Got all the fruits!\");\n          }\n        });\n      }\n    });\n\n  }\n});\n```\n\n### Providing serializable messages\nIn addition to types supported by the Vert.x event bus, the Vertigo messaging\nframework supports any `Serializable` Java object.\n\n```java\npublic class MyMessage implements Serializable {\n  private String foo;\n  private int bar;\n\n  public MyMessage(String foo, int bar) {\n    this.foo = foo;\n    this.bar = bar;\n  }\n}\n```\n\n### Sending and receiving files\nThe Vertigo utilities helper module provides additional APIs for handling special\ncases such as sending large files through ports. The utility project's `FileSender`\nutility can send any size file on an output port using output groups.\n\nTo use the file sender, simply construct a new `FileSender`, passing any `Output`\ninstance (a port, batch, or group) to the sender.\n\n```java\nFileSender sender = new FileSender(output.port(\"file\"));\n```\n\nThen, to send a file pass the string name of the file to the `sendFile` method.\n\n```java\nsender.sendFile(\"hello.txt\");\n```\n\nOn the other side, to receive a file use the `FileReceiver` utility. The file receiever\nwill store a temporary file on the receiving node.\n\n```java\nFileReceiver receiver = new FileReceiver(input.port(\"file\"));\nreceiver.fileHandler(new Handler\u003cString\u003e() {\n  public void handle(String filePath) {\n    AsyncFile file = vertx.fileSystem().openSync(filePath);\n  }\n});\n```\n\nThe `String` passed to the `fileHandler` will be the full path to the temporary file.\nRemember to delete the file once you're done with it!\n\nThe `FileSender` and `FileReceiver` work by using output/input groups to stream file\ncontents from one component to another. Vertigo guarantees ordering of messages\nand guarantees that all messages within a given group will go to the same target\ninstance(s). To see how these helpers are implemented see the\n[FileSender](https://github.com/kuujo/vertigo/tree/master/util/src/main/java/net/kuujo/vertigo/io/FileSender.java)\nand [FileReceiver](https://github.com/kuujo/vertigo/tree/master/util/src/main/java/net/kuujo/vertigo/io/FileReceiver.java)\nclasses.\n\n## Network Deployment and Clustering\nVertigo provides its own cluster management framework on top of the Vert.x cluster.\nEach Vertigo network will always be deployed in a Vertigo cluster. Vertigo clusters\ncan be deployed either within a single, non-clustered Vert.x instance or across a\nVert.x cluster. Clusters provide a logical separation between different applications\nwithin a Vert.x cluster and provide additional features such as failover.\n\n### Starting a cluster from the command line\nVertigo provides a special Vert.x module for starting a Vertigo cluster agent. To\nstart a cluster node simply start the `net.kuujo~vertigo-cluster~0.7.0-RC2` module.\n\n```\nvertx runmod net.kuujo~vertigo-cluster~0.7.0-RC2\n```\n\nThe cluster agent accepts a few important configuration options:\n* `cluster` - the event bus address of the cluster to which the node belongs. Defaults\n   to `vertigo`\n* `group` - the HA group to which the node belongs. For simplicity, the Vertigo HA\n  mechanism is modeled on the core Vert.x HA support.\n* `address` - the event bus address of the node. Defaults to a `UUID` based string.\n* `quorum` - the HA quorum size. See the Vert.x HA documentation on quorums.\n\n### Starting a cluster programmatically\nVertigo also provides an API for deploying clusters or individual nodes through the\nVert.x `Container`.\n\n```java\nVertigo vertigo = new Vertigo(this);\nvertigo.deployCluster(\"test-cluster\", new Handler\u003cAsyncResult\u003cCluster\u003e\u003e() {\n  public void handle(AsyncResult\u003cCluster\u003e result) {\n    Cluster cluster = result.result();\n  }\n});\n```\n\nThere are several methods for deploying nodes or clusters within the current\nVert.x instance.\n\n* `deployCluster(String address)`\n* `deployCluster(String address, Handler\u003cAsyncResult\u003cCluster\u003e\u003e doneHandler)`\n* `deployCluster(String address, int nodes)`\n* `deployCluster(String address, int nodes, Handler\u003cAsyncResult\u003cCluster\u003e\u003e doneHandler)`\n\nUsers should use this API rather than deploying the `ClusterAgent` verticle directly\nbecause the cluster agent is pluggable. To override the default cluster agent\nset the system property `net.kuujo.vertigo.cluster`.\n\n### Referencing a cluster programmatically\nNetwork deployments are performed through the `Cluster` API. To get a\n`Cluster` instance for a running Vertigo cluster call the `getCluster` method\n\n```java\nCluster cluster = vertigo.getCluster(\"test-cluster\");\n```\n\n### Accessing a cluster through the event bus\nThe cluster system is built on worker verticles that are accessed over the event bus.\nCluster agents expose an event bus API that can be used as an alternative to the\nJava API. Since all Java interface methods simply wrap the event bus API, you can\nperform all the same operations as are available through the API over the event bus.\n\nTo send a message to a cluster simply send the message to the cluster address.\n\n```java\nJsonObject message = new JsonObject()\n    .putString(\"action\", \"check\")\n    .putString(\"network\", \"test\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObejct\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      boolean isDeployed = reply.body().getBoolean(\"result\");\n    }\n  }\n});\n```\n\nEach message must contain an `action` indicating the action to perform. Each API\nmethod has an action associated with it, and the actions and their arguments will\nbe outline in the following documentation.\n\n### Deploying a network\nTo deploy a network use the `deployNetwork` methods on the `Cluster` for\nthe cluster to which the network should be deployed.\n\n```java\nNetworkConfig network = vertigo.createNetwork(\"test\");\nnetwork.addComponent(\"foo\", \"foo.js\", 2);\nnetwork.addComponent(\"bar\", \"bar.py\", 4);\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\");\n\ncluster.deployNetwork(network);\n```\n\nWhen the network is deployed, the cluster will check to determine whether a\nnetwork of the same name is already running in the cluster. If a network of\nthe same name is running, the given network configuration will be *merged*\nwith the running network's configuration and the missing components will be\ndeployed. This is very important to remember. Deployment will *not* fail if\nyou deploy a network with the same name of a network that already running\nin the given cluster.\n\nTo determine when the network has been successfully deployed pass an `AsyncResult`\nhandler to the `deployNetwork` method.\n\n```java\ncluster.deployNetwork(network, new Handler\u003cAsyncResult\u003cActiveNetwor\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    if (result.succeeded()) {\n      ActiveNetwork network = result.result();\n    }\n  }\n});\n```\n\nYou can also deploy the network from the `Vertigo` API by naming the cluster\nto which to deploy the network.\n\n```java\nvertigo.deployNetwork(\"test-cluster\", network, new Handler\u003cAsyncResult\u003cActiveNetwor\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    if (result.succeeded()) {\n      ActiveNetwork network = result.result();\n    }\n  }\n});\n```\n\n### Deploying a network from JSON\nNetworks can be deployed programmatically from JSON configurations. To deploy\na network from JSON configuration simply pass the `JsonObject` configuration\nin place of the `NetworkConfig`\n\n```java\nJsonObject network = new JsonObject()\n    .putString(\"name\", \"test\")\n    .putObject(\"components\", new JsonObject()\n        .putObject(\"foo\", new JsonObject()\n            .putString(\"type\", \"verticle\").putString(\"main\", \"foo.js\")));\n\ncluster.deployNetwork(network);\n```\n\nJSON configurations can also be used to deploy networks to a cluster over the\nevent bus. To deploy a network over the event bus send a `deploy` message to\nthe cluster address with a `network` type, specifying the `network` configuration\nas a `JsonObject`.\n\n```\n{\n  \"action\": \"deploy\",\n  \"type\": \"network\",\n  \"network\": {\n    \"name\": \"test\",\n    \"components\": {\n      \"foo\": {\n        \"type\": \"verticle\",\n        \"main\": \"foo.js\"\n      }\n    }\n  }\n}\n```\n\nIf successful, the cluster will reply with a `status` of `ok`.\n\n```java\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      // Network was successfully deployed!\n    }\n  }\n});\n```\n\nFor information on the JSON configuration format see\n[creating networks from json](#creating-networks-from-json)\n\n### Undeploying a network\nTo undeploy a *complete* network from a cluster call the `undeployNetwork`\nmethod, passing the network name as the first argument.\n\n```java\ncluster.undeployNetwork(\"test\", new Handler\u003cAsyncResult\u003cVoid\u003e\u003e() {\n  public void handle(AsyncResult\u003cVoid\u003e result) {\n    if (result.succeeded()) {\n      // Network has been undeployed.\n    }\n  }\n});\n```\n\nThe `AsyncResult` handler will be called once all the components within the network\nhave been undeployed from the cluster.\n\nThe `undeployNetwork` method also supports a `NetworkConfig`. The configuration based\nundeploy method behaves similarly to the `deployNetwork` method in that the given\nconfiguration will be *unmerged* from the configuration that's running in the cluster.\nIf the configuration lists all the components that are present in the running network\nthen the network will be completely undeployed, otherwise only the listed components\nwill be undeployed and the network will continue to run. For this reason it is\n*strongly recommended* that you undeploy a network by name if you intend to undeploy\nthe entire network.\n\nLike the `deployNetwork` method, `undeployNetwork` has an equivalent event bus based\naction. To undeploy a network over the event bus use the `undeploy` action, specifying\n`network` as the `type` to undeploy along with the `network` to undeploy.\n\n```\n{\n  \"action\": \"undeploy\",\n  \"type\": \"network\",\n  \"network\": \"test\"\n}\n```\n\nThe `network` field can also contain a JSON configuration to undeploy. If the undeployment\nis successful, the cluster will reply with a `status` of `ok`.\n\n```java\nJsonObject message = new JsonObject()\n  .putString(\"action\", \"undeploy\")\n  .putString(\"type\", \"network\")\n  .putString(\"network\", \"test\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      // Network was successfully undeployed!\n    }\n  }\n});\n```\n\n### Checking if a network is deployed\nTo check if a network is deployed in the cluster use the `isDeployed` method.\n\n```java\ncluster.isDeployed(\"test\", new Handler\u003cAsyncResult\u003cBoolean\u003e\u003e() {\n  public void handle(AsyncResult\u003cBoolean\u003e result) {\n    if (result.succeeded()) {\n      boolean deployed = result.result(); // Whether the network is deployed.\n    }\n  }\n});\n```\n\nWhen checking if a network is deployed, a `check` message will be sent to the cluster along\nwith the name of the network to check. If the network's configuration is available in\nthe cluster then the network will be considered deployed. This is the same check that\nthe cluster uses to determine whether a network is already deployed when deploying a\nnew network configuration.\n\nTo check whether a network is deployed directly over the event bus, send a `check` message\nto the cluster specifying a `network` type along with the `network` name.\n\n```\n{\n  \"action\": \"check\",\n  \"type\": \"network\",\n  \"network\": \"test\"\n}\n```\n\nSend the `check` message to the cluster event bus address. If successful, the cluster will\nreply with a boolean `result` indicating whether the network is deployed in the cluster.\n\n```java\nJsonObject message = new JsonObject()\n  .putString(\"action\", \"check\")\n  .putString(\"type\", \"network\")\n  .putString(\"network\", \"test\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      boolean deployed = reply.body().getBoolean(\"result\");\n    }\n  }\n});\n```\n\n### Listing networks running in a cluster\nTo list the networks running in a cluster call the `getNetworks` method.\n\n```java\ncluster.getNetworks(new Handler\u003cAsyncResult\u003cCollection\u003cActiveNetwork\u003e\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    ActiveNetwork network = result.result();\n  }\n});\n```\n\nNote that the method returns an `ActiveNetwork`. The active network can be used\nto reconfigure the running network, but more on that later. The current network\nconfiguration can be retrieved from the `ActiveNetwork` by calling the `getConfig`\nmethod.\n\n```java\nNetworkConfig config = network.getConfig();\n```\n\nTo list the networks running in the cluster over the event bus, use the `list`\naction.\n\n```\n{\n  \"action\": \"list\"\n}\n```\n\nIf successful, the cluster will reply with a `result` containing an array of\nconfiguration objects for each network running in the cluster.\n\n```java\nJsonObject message = new JsonObject()\n  .putStrign(\"action\", \"list\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      JsonArray networks = reply.body().getArray(\"result\");\n    }\n  }\n});\n```\n\n### Deploying a bare network\nVertigo networks can be reconfigured after deployment, so sometimes it's useful\nto deploy an empty network with no components or connections.\n\n```java\ncluster.deployNetwork(\"test\", new Handler\u003cAsyncResult\u003cActiveNetwork\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    ActiveNetwork network = result.result();\n  }\n});\n```\n\nWhen a bare network is deployed, Vertigo simply deploys a network manager\nverticle with no components. Once the network is reconfigured, the manager\nwill automatically update the network with any new components.\n\nTo deploy a bare network over the event bus, pass a `String` network name\nin the `network` field rather than a JSON network configuration.\n\n```java\nJsonObject message = new JsonObject()\n  .putString(\"action\", \"deploy\")\n  .putString(\"type\", \"network\")\n  .putString(\"network\", \"test\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n      // Network was successfully deployed!\n    }\n  }\n});\n```\n\n### Reconfiguring a network\nVertigo provides several methods to reconfigure a network after it has been\ndeployed. After a network is deployed users can add or remove components or\nconnections from the network. To reconfigure a running network simply deploy\nor undeploy a network configuration of the same name.\n\n```java\n// Create and deploy a two component network.\nNetworkConfig network = vertigo.createNetwork(\"test\");\nnetwork.addComponent(\"foo\", \"foo.js\", 2);\nnetwork.addComponent(\"bar\", \"bar.py\", 4);\n\nvertigo.deployNetwork(\"test-cluster\", network, new Handler\u003cAsyncResult\u003cActiveNetwork\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    // Create and deploy a connection between the two components.\n    NetworkConfig network = vertigo.createNetwork(\"test\");\n    network.createConnection(\"foo\", \"out\", \"bar\", \"in\");\n    vertigo.deployNetwork(\"test-cluster\", network);\n  }\n});\n```\n\nWhen a network is deployed, the cluster will check to see if any other networks\nof the same name are already deployed. If a network of the same name is deployed\nthen the new configuration will be merged with the running configuration.\nSimilarly, when undeploying a network from configuration, the cluster will undeploy\nonly the components and connections listed in a connection. The network will only\nbe completely undeployed if the configuration lists all the components deployed in\nthe network.\n\nVertigo queues configuration changes internally to ensure that only one configuration\nchange can occur at any given time. So if you separately deploy two connections,\nthe second connection will not be added to the network until the first has been\nadded and connected on all relevant components. To deploy more than one component\nor connection to a running network simultaneously just list them in the same\nconfiguration.\n\nJust as networks can be deployed and undeployed over the event bus, they can also\nbe reconfigured by sending `deploy` and `undeploy` messages to the cluster.\n\n### Working with active networks\nVertigo provides a special API for reconfiguring running networks known as the\n*active network*. The `ActiveNetwork` API mimics the network configuration API,\nexcept changes to an `ActiveNetwork` instance will be immediately deployed to\nthe running network in the appropriate cluster.\n\nTo load an active network you can call `getNetwork` on a cluster.\n\n```java\ncluster.getNetwork(\"test\", new Handler\u003cAsyncResult\u003cActiveNetwork\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    ActiveNetwork network = result.result();\n    network.createConnection(\"foo\", \"out\", \"bar\", \"in\");\n  }\n});\n```\n\nThe active network API also supports `AsyncResult` handlers so you can determine\nwhen the network has been updated with the new configuration.\n\n```java\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\", new Handler\u003cAsyncResult\u003cActiveNetwork\u003e\u003e() {\n  public void handle(AsyncResult\u003cActiveNetwork\u003e result) {\n    // Connection has been added and connected.\n  }\n});\n```\n\nEach `ActiveNetwork` also contains an internal `NetworkConfig` which can be\nretrieved by the `getConfig` method.\n\n```java\nNetworkConfig config = network.getConfig();\n```\n\nThe active network's internal `NetworkConfig` will be automatically updated when\nthe running network configuration is updated.\n\n### Deploying a network from the command line\nVertigo provides a special facility for deploying networks from json configuration files.\nThis feature is implemented as a Vert.x language module, so the network deployer must\nbe first added to your `langs.properties` file.\n\n```\nnetwork=net.kuujo~vertigo-deployer~0.7.0-RC2:net.kuujo.vertigo.NetworkFactory\n.network=network\n```\n\nYou can replace the given extension with anything that works for you. Once the language\nmodule has been configured, simply run a network configuration file like any other\nVert.x verticle.\n\n```\nvertx run my_network.network\n```\n\nThe `NetworkFactory` will construct the network from the json configuration file and\ndeploy the network to the available cluster.\n\n## Cluster Management\nVertigo clusters support remote deployments of networks and modules/verticles and\nshared data access over the event bus. Vertigo provides a Java and event bus API\nfor all cluster operations.\n\n### Accessing the cluster from within a component\nThe Vertigo cluster is made available to users through the `cluster` field within\nthe `ComponentVerticle` class. The `cluster` within any given component will always\nreference the Vertigo cluster to which the component's parent network belongs. This\nmeans that deployments made through the `cluster` will be separated in the same\nway that networks are separated from each other across clusters.\n\n### Deploying modules and verticles to the cluster\nThe Vertigo cluster supports remote deployment of modules and verticles over the\nevent bus. The `Cluster` API wraps the event bus API and mimics the core Vert.x\n`Container` interface. To deploy a module or verticle simply call the appropriate\nmethod on the component `Cluster` instance:\n\n```java\npublic class MyComponent extends ComponentVerticle {\n\n  @Override\n  public void start() {\n    cluster.deployVerticle(\"foo.js\", new Handler\u003cAsyncResult\u003cString\u003e\u003e() {\n      public void handle(AsyncResult\u003cString\u003e result) {\n        if (result.succeeded()) {\n          // Successfully deployed the verticle!\n        }\n      }\n    });\n  }\n\n}\n```\n\nThe `Cluster` API behaves exactly like the Vert.x `Container` API and exposes an\nidentical deployment interface. But Vertigo clusters can be separated by event\nbus addresses. So, when deploying or undeploying verticles or modules, it's important\nthat you communicate with the correct cluster. The cluster that is available from\nwithin components will always be the cluster in which the component is running.\n\n### Undeploying modules and verticles from the cluster\nTo undeploy a module or verticle from the cluster call the `undeployModule` or\n`undeployVerticle` method just as with the Vert.x `Container`.\n\n```java\ncluster.undeployVerticle(deploymentID);\n```\n\n### Working with cluster groups\nVertigo clusters can be separated into groups, allowing components, modules, or\nverticles to be deployed only within specific cluster groups.\n\nTo get a reference to a cluster group, call the `getGroup` method on a `Cluster`\ninstance.\n\n```java\ncluser.getGroup(\"foo\", new Handler\u003cAsyncResult\u003cGroup\u003e\u003e() {\n  public void handle(AsyncResult\u003cGroup\u003e result) {\n    if (result.succeeded()) {\n      result.result().deployVerticle(\"bar.js\");\n    }\n  }\n});\n```\n\nIf the group doesn't exist in the cluster then a `ClusterException` will be\nreturned to the `AsyncResult` handler.\n\n## Cluster-wide shared data\nCluster-wide shared data structures are made available via the same API as clustering.\nIf the current Vert.x instance is a Hazelcast clustered instance then cluster-wide\nshared data structures will be backed by Hazelcast data structures. If the current\nVert.x instance is not clustered then data structures will be backed by Vert.x\n`SharedData` structures.\n\nThe cluster API is available in all components via the `cluster` field of the\n`ComponentVerticle`.\n\n### AsyncMap\nThe `AsyncMap` interface closely mimics the interface of the Java `Map` interface,\nbut uses `Handler\u003cAsyncResult\u003cT\u003e\u003e` rather than return values.\n\n```java\nfinal AsyncMap\u003cString, String\u003e map = cluster.getMap(\"foo\");\nmap.put(\"foo\", \"bar\", new Handler\u003cAsyncResult\u003cString\u003e\u003e() {\n  public void handle(AsyncResult\u003cString\u003e result) {\n    if (result.succeeded()) {\n      map.get(\"foo\", new Handler\u003cAsyncResult\u003cString\u003e\u003e() {\n        public void handle(AsyncResult\u003cString\u003e result) {\n          if (result.succeeded()) {\n            String foo = result.result();\n          }\n        }\n      });\n    }\n  }\n});\n```\n\nIf the Vert.x instance is not clustered then Vertigo maps will be backed by\nthe Vert.x `ConcurrentSharedMap`. If the Vert.x instance is clustered then maps\nwill be backed by Hazelcast maps that are accessed over the event bus through\nthe Vertigo cluster.\n\n### AsyncSet\nThe `AsyncSet` interface closely mimics the interface of the Java `Set` interface,\nbut uses `Handler\u003cAsyncResult\u003cT\u003e\u003e` rather than return values.\n\n```java\nfinal AsyncSet\u003cString\u003e set = cluster.getSet(\"foo\");\nset.add(\"bar\", new Handler\u003cAsyncResult\u003cBoolean\u003e\u003e() {\n  public void handle(AsyncResult\u003cBoolean\u003e result) {\n    if (result.succeeded()) {\n      set.remove(\"bar\");\n    }\n  }\n});\n```\n\nIf the Vert.x instance is not clustered then Vertigo sets will be backed by\nthe Vert.x `SharedData` sets. If the Vert.x instance is clustered then sets\nwill be backed by Hazelcast sets that are accessed over the event bus through\nthe Vertigo cluster.\n\n### AsyncList\nThe `AsyncList` interface closely mimics the interface of the Java `List` interface,\nbut uses `Handler\u003cAsyncResult\u003cT\u003e\u003e` rather than return values.\n\n```java\nAsyncList\u003cString\u003e list = cluster.getList(\"foo\");\nlist.add(\"bar\", new Handler\u003cAsyncResult\u003cBoolean\u003e\u003e() {\n  public void handle(AsyncResult\u003cBoolean\u003e result) {\n    if (result.succeeded()) {\n      list.remove(0);\n    }\n  }\n});\n```\n\nIf the Vert.x instance is not clustered then Vertigo lists will be backed by\na custom list implementation on top of the Vert.x `ConcurrentSharedMap`. If the\nVert.x instance is clustered then lists will be backed by Hazelcast lists that are\naccessed over the event bus through the Vertigo cluster.\n\n### AsyncQueue\nThe `AsyncQueue` interface closely mimics the interface of the Java `Queue` interface,\nbut uses `Handler\u003cAsyncResult\u003cT\u003e\u003e` rather than return values.\n\n```java\nfinal AsyncQueue\u003cString\u003e queue = cluster.getQueue(\"foo\");\nqueue.add(\"bar\", new Handler\u003cAsyncResult\u003cBoolean\u003e\u003e() {\n  public void handle(AsyncResult\u003cBoolean\u003e result) {\n    if (result.succeeded()) {\n      queue.poll(new Handler\u003cAsyncResult\u003cString\u003e\u003e() {\n        public void handle(AsyncResult\u003cString\u003e result) {\n          if (result.succeeded()) {\n            String value = result.result();\n          }\n        }\n      });\n    }\n  }\n});\n```\n\nIf the Vert.x instance is not clustered then Vertigo queues will be backed by\na custom queue implementation on top of the Vert.x `ConcurrentSharedMap`. If the\nVert.x instance is clustered then queues will be backed by Hazelcast queues that are\naccessed over the event bus through the Vertigo cluster.\n\n### AsyncCounter\nThe `AsyncCounter` facilitates generating cluster-wide counters.\n\n```java\nAsyncCounter counter = cluster.getCounter(\"foo\");\ncounter.incrementAndGet(new Handler\u003cAsyncResult\u003cLong\u003e\u003e() {\n  public void handle(AsyncResult\u003cLong\u003e result) {\n    if (result.succeeded()) {\n      long value = result.result();\n    }\n  }\n});\n```\n\nIf the Vert.x instance is not clustered then Vertigo counters will be backed by\na custom counter implementation on top of the Vert.x `ConcurrentSharedMap`. If the\nVert.x instance is clustered then counters will be backed by Hazelcast maps that are\naccessed over the event bus through the Vertigo cluster.\n\n### Accessing shared data over the event bus\nAs with network and module/verticle deployments, cluster-wide shared data structures\ncan be accessed directly over the event bus. Data actions relate directly to their\nAPI methods. Each shared data message must contain a `type` and the `name` of the\ndata structure to which the message refers. For example, to `put` a value in the\n`foo` map we do the following:\n\n```java\n// Put key \"bar\" to \"baz\" in map \"foo\"\nJsonObject message = new JsonObject()\n  .putString(\"type\", \"map\")\n  .putString(\"name\", \"foo\")\n  .putString(\"action\", \"put\")\n  .putString(\"key\", \"bar\")\n  .putString(\"value\", \"baz\");\nvertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n  public void handle(Message\u003cJsonObject\u003e reply) {\n    if (reply.body().getString(\"status\").equals(\"ok\")) {\n\n      // Get the value of key \"bar\" in map \"foo\"\n      JsonObject message = new JsonObject()\n        .putString(\"type\", \"map\")\n        .putString(\"name\", \"foo\")\n        .putString(\"action\", \"get\")\n        .putString(\"key\", \"bar\");\n      vertx.eventBus().send(\"test-cluster\", message, new Handler\u003cMessage\u003cJsonObject\u003e\u003e() {\n        public void handle(Message\u003cJsonObject\u003e reply) {\n          if (reply.body().getString(\"status\").equals(\"ok\")) {\n            String value = reply.body().getString(\"result\");\n          }\n        }\n      });\n\n    }\n  }\n});\n```\n\n## Hooks\nVertigo provides a special mechanism for hooking into component and messaging\nevents. Hooks are objects that are added to the network configuration and receive\nnotifications when certain events occur. All hooks implement the `JsonSerializable`\ninterface which handles JSON serialization with Jackson. In most cases, users\ncan simply implement the relevant hook interface and Vertigo will handle serialization\nof basic fields automatically. You can use Jackson annotations to ignore certain\nfields or provide custom serialization as necessary.\n\n### InputHook\nInput hooks can be used to hook into message events related to the target port\non a specific connection within a network configuration. Input hooks are added\nto the `target` element of a `ConnectionConfig`.\n\nTo define an input hook implement the `InputHook` interface.\n\n```java\npublic class MyInputHook implements InputHook {\n\n  @Override\n  public void handleReceive(Object message) {\n  \n  }\n\n}\n```\n\nThe `InputHook` interface requires only a single `handleReceive` method which\nwill be called whenever a message is received on the connection.\n\nTo add the hook to a connection use the `addHook` method on a `ConnectionConfig.Target`\ninstance.\n\n```java\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\").getTarget().addHook(new MyInputHook());\n```\n\n### OutputHook\nOutput hooks can be used to hook into message events related to the source port\non a specific connection within a network configuration. Output hooks are added\nto the `source` element of a `ConnectionConfig`.\n\nTo define an output hook implement the `OutputHook` interface.\n\n```java\npublic class MyOutputHook implements OutputHook {\n\n  @Override\n  public void handleSend(Object message) {\n  \n  }\n\n}\n```\n\nThe `OutputHook` interface requires only a single `handleSend` method which\nwill be called whenever a message is sent on the connection.\n\nTo add the hook to a connection use the `addHook` method on a `ConnectionConfig.Source`\ninstance.\n\n```java\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\").getSource().addHook(new MyOutputHook());\n```\n\n### IOHook\nI/O hooks are a combination of the `InputHook` and `OutputHook` interfaces. When an\nI/O hook is added to a connection, its methods will be called when an event occurs\non either side of the connection. For the sending side of the connection, the hook\nwill be called when a message is sent, and for the receiving side of the connection,\nthe hook will be called when a message is received.\n\n```java\npublic class MyIOHook implements IOHook {\n\n  @Override\n  public void handleSend(Object message) {\n  \n  }\n\n  @Override\n  public void handleReceive(Object message) {\n  \n  }\n\n}\n```\n\nTo add the hook to a connection use the `addHook` method on a `ConnectionConfig` instance.\n\n```java\nnetwork.createConnection(\"foo\", \"out\", \"bar\", \"in\").addHook(new MyIOHook());\n```\n\n### ComponentHook\nComponents hooks are component-level hooks that implement both the `InputHook`\nand `OutputHook` interfaces along with some additional component-level hook methods.\nSince component hooks are added at the component level, the `handleSend` and\n`handleReceive` methods will be called each time a message is sent or received\non *any* port. Additionally, the component hook can receive notifications of when\nthe component has started and stopped as well.\n\n```java\npublic class MyComponentHook implements ComponentHook {\n\n  @Override\n  public void handleStart(Component component) {\n  \n  }\n\n  @Override\n  public void handleSend(Object message) {\n  \n  }\n\n  @Override\n  public void handleReceive(Object message) {\n  \n  }\n\n  @Override\n  public void handleStop(Component component) {\n  \n  }\n\n}\n```\n\nThe `handleStart` and `handleStop` will be passed the internal Vertigo\n`Component` instance which contains all fields available to the Java `ComponentVerticle`\nalong with additional information about the component configuration.\n\nComponent hooks are added to `ComponentConfig` instances within the network configuration.\n\n```java\nnetwork.addComponent(\"foo\", \"foo.js\", 2).addHook(new MyComponentHook());\n```\n\n## Logging\nEach Vertigo component contains a special `PortLogger` which logs messages\nto component output ports in addition to standard Vert.x log files. This allows\nother components to listen for log messages on input ports.\n\nThe `PortLogger` logs to ports named for each logger method:\n* `fatal`\n* `error`\n* `warn`\n* `info`\n* `debug`\n* `trace`\n\n### Logging messages to output ports\nThe `PortLogger` simple implements the standard Vert.x `Logger` interface.\nSo, to log a message to an output port simply call the appropriate log method:\n\n```java\npublic class MyComponent extends ComponentVerticle {\n\n  @Override\n  public void start() {\n    logger.info(\"Component started successfully!\");\n  }\n\n}\n```\n\n### Reading log messages\nTo listen for log messages from a component, simply add a connection to a network\nconfiguration listening on the necessary output port. For instance, you could\naggregate and count log messages from one component by connecting each log port to\na single input port on another component.\n\n```java\nNetworkConfig network = vertigo.createNetwork(\"log-test\");\nnetwork.addVerticle(\"logger\", \"logger.js\", 2);\nnetwork.addVerticle(\"log-reader\", LogReader.class.getName(), 2);\nnetwork.createConnection(\"logger\", \"fatal\", \"log-reader\", \"log\").hashSelect();\nnetwork.createConnection(\"logger\", \"error\", \"log-reader\", \"log\").hashSelect();\nnetwork.createConnection(\"logger\", \"warn\", \"log-reader\", \"log\").hashSelect();\nnetwork.createConnection(\"logger\", \"info\", \"log-reader\", \"log\").hashSelect();\nnetwork.createConnection(\"logger\", \"debug\", \"log-reader\", \"log\").hashSelect();\nnetwork.createConnection(\"logger\", \"trace\", \"log-reader\", \"log\").hashSelect();\n```\n\nWith a hash selector on each connection, we guarantee that the same log message\nwill always go to the same `log-reader` instance.\n\nLog messages will arrive as simple strings:\n\n```java\npublic class LogReader extends ComponentVerticle {\n  private final Map\u003cString, Integer\u003e counts = new HashMap\u003c\u003e();\n\n  @Override\n  public void start() {\n    input.port(\"log\").messageHandler(new Handler\u003cString\u003e() {\n      public void handle(String message) {\n        // Update the log message count.\n        if (!counts.containsKey(message)) {\n          counts.put(message, 1);\n        } else {\n          counts.put(message, counts.get(message) + 1);\n        }\n        output.port(\"count\").send(counts.get(message)); // Send the updated count.\n      }\n    });\n  }\n\n}\n```\n\n## How it works\nThere are four essential components to Vertigo's design:\n* [Configurations](#configurations)\n* [Cluster](#cluster)\n* [Networks](#networks-2)\n* [Components](#components-2)\n* [Communication](#communication)\n\nThis section outlines how each of the components of Vertigo is designed and how\nthey interact with one another in order to support advanced features such as\nfault-tolerant deployments, runtime configuration changes, strongly-ordered\nmessaging, and exactly-once processing.\n\n### Configurations\nAt the core of Vertigo's networks are immutable configurations called contexts.\nEvery element of a network has an associated context. When a network is first\ndeployed, Vertigo constructs a version-controlled context from the network's\nconfiguration. This is the point at which Vertigo generates things like unique\nIDs and event bus addresses.\n\n[ContextBuilder](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/impl/ContextBuilder.java)\n\nThe context used by each element for setup tasks such as connecting to the\ncluster, creating ports and connections, and registering hooks.\n\n### Cluster\nThe Vertigo cluster is the component that manages deployment, undeployment,\nand monitoring of networks and their components. Vertigo clusters consist of\none or more special verticles that expose an event bus interface to deploying\nmodules, verticles, and complete networks as well as cluster-wide shared data.\n\nThe verticle implementation that handles clustering is the\n[ClusterAgent](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/manager/impl/ClusterAgent.java)\nThe cluster agent exposes an event bus API for performing cluster operations,\nincluding remote module and verticle deployments, failover, and cluster-wide\nshared data, along with of course deploying and managing networks.\n\nThe Vertigo cluster makes heavy use of cluster-wide shared data for coordination.\nThis is the element of the cluster that supports deploying/undeploying partial\nnetwork configurations. When a network is deployed to the cluster, the cluster\nwill first [determine whether a network of the same name is already deployed in\nthe cluster](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/impl/ClusterAgent.java#L267).\nIf the network is running in the cluster, the cluster will load the running network's\nconfiguration and [merge the new configuration with the existing configuration](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/impl/ClusterAgent.java#L258),\notherwise the network will be completely deployed.\n\n### Networks\nBut the cluster doesn't ever actually deploy any of the network's components.\nInstead, the cluster simply deploys a special verticle called the\n[network manager](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/network/manager/NetworkManager.java)\nwhich handles deployment/undeployment of components and coordinates startup\nand shutdown of networks. Rather than communicating over the event bus, the\ncluster and the network communicate using data-driven events through shared\ndata structures. When the cluster wants to update a network, it [sets the\nnetwork's configuration key](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/impl/ClusterAgent.java#L333)\nin the cluster. On the other side, the manager watches the configuration key\nfor changes using Vertigo's internal [WatchableAsyncMap](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/data/WatchableAsyncMap.java).\nSimilarly, the network\n[sets a status key](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/cluster/impl/ClusterAgent.java#L308)\nonce the configuration has been installed and the cluster watches the network's\nstatus key to determine when the network has completed configuration. This\nallows Vertigo's networks to be dynamically altered and network configurations\nto be persisted in the cluster through crashes so they can easily recover.\n\nSince each network manager always monitors the network's configuration for\nchanges, it is automatically notified when the cluster updates the configuration.\nWhen a network configuration change occurs, the manager will first\n[unset the network's status key](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/network/manager/NetworkManager.java#L427)\nto indicate that the network is not currently completely set up. This gives the\nnetwork's components an opportunity to pause if necessary. Once the status key\nhas been unset the network will [undeploy any removed components](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/network/manager/NetworkManager.java#L323)\nand then [deploy any new components](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/network/manager/NetworkManager.java#L354).\nWhile new components are being added, the manager will also update each component's\nconfiguration in the cluster. With components also watching their own configurations\nfor changes, this allows components to update their internal connections without\nbeing undeployed, but more on that in the next section. It's important to note that\n[all configuration changes are queued in a task runner](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/util/TaskRunner.java)\nthat ensures that only one configuration change can ever be processed at any given\ntime.\n\n### Components\nOne of the challenges when starting up multiple verticles across a cluster is\ncoordinating startup. If a component begins sending messages on a connection\nbefore the other side is listening, messages will be lost. It is the responsibility\nof the [component coordinator](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/component/impl/DefaultComponentCoordinator.java)\nto notify the cluster once a component has completed startup.\n\nTo do so, coordinators use the same mechanism that clusters and network managers\nuse to communicate status information - cluster-wide shared data. When a component\nfirst starts up, it immediately\n[loads its current context from the cluster](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/component/impl/DefaultComponentCoordinator.java#L100)\nand watches its configuration key for changes. Once its definite context has\nbeen loaded, the component will open its input and output collectors. Finally,\nonce the component's input and output have been opened, the coordinator will\nset the component's status key in the cluster, indicating that the component\nhas completed startup. However, even though the component has indicated to the\nnetwork that it has completed startup, the component won't actually start [until\nthe network has indicated](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/component/impl/DefaultComponent.java#L148)\nthat *all* the active components in the network have completed setup.\n\nWhen the network's configuration changes, the network manager will set the\ncomponent's configuration key in the cluster. By watching the configuration key,\nthe component's internal configuration will be automatically updated if any\nchanges occur. With cluster-wide data events, since all contexts are\n[Observable](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/util/Observable.java),\ncomponents can watch their configurations for changes that were made in cluster-wide\ndata structures. When a component configuration change occurs, each of the component's\ninternal input and output ports will *automatically* recognize the change and\n[update their connections](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/port/impl/DefaultOutputPort.java#L83).\nAs with networks, components ensure that only one configuration change can\never occur at any given time.\n\n### Communication\nOne of the most important features in Vertigo is its messaging system. The\nmessaging framework has been completely redesigned in Vertigo 0.7 to be modeled\non ports. All Vertigo's messaging is performed over the Vert.x event bus, and\nthe messaging system is designed to provide strongly-ordered and exactly-once\nsemantics.\n\nThere are numerous components to the Vertigo communication framework. At the\nhighest level, each component has an `InputCollector` and an `OutputCollector`.\n\nInternally, Vertigo uses *streams* to model connections between an output port\non one set of component instances and an input port on another set of component\ninstances. Each output port can contain any number of output streams, and each\noutput stream can contain any number of output connections (equal to the number\nof instances of the target component). Connections represent a single event bus\naddress connection between two instances of two components on a single Vertigo\nconnection. Connection selectors are used at the stream level to select a set\nof connections to which to send each message for the stream.\n\nVertigo provides strong ordering and exactly-once semantics through a unique,\nhigh-performance algorithm wherein messages are essentially batched between\nconnections. When a message is sent on an output connection, the connection\ntags the message with a monotonically increasing number and the message is\nstored in an internal `TreeMap` with the ID as the key. Since Vertigo ensures\nthat each output connection will only ever communicate with a single input\nconnection, this monotonically increasing number can be used to check the\norder of messages received. Input connections simply store the ID of the\nlast message they received. When a new message is received, if the ID is\nnot one plus the last seen ID, the input connection will immediately\n[send a *fail* message](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultInputConnection.java#L218)\nback to the output connection, indicating the last message\nthat the input connection received in order. The output connection will then begin\n[resending all stored messages in order](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultOutputConnection.java#L342)\nafter that point. If no messages are received out of order, the input\nconnection will periodically\n[send an *ack* message](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultInputConnection.java#L205)\nto the output connection indicating the last message received.\nThe output connection will then\n[purge its internal storage](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultOutputConnection.java#L328)\nof all messages before the indicated identifier. This simple algorithm\nallows Vertigo to guarantee strongly-order/exactly-once processing without\nthe use of event bus reply handlers.\n\nThe Vertigo communication framework also supports a couple of different\nforms of batching - *batches* and *groups*.\n\nBatches are unique collections of messages *emitted* from a given component\ninstance. Batches are represented on *all* streams within a given port\nduring their lifespan. Alternatively, groups are collections of messages\n*received* by a given component. That is, groups relate only to a single\nstream on a given output port. Additionally, each output port may only\nhave a single batch open at any given time whereas multiple groups can\nbe open at any given time.\n\nWhen a batch is created, since batches relate to all connections in all\nstreams, *each output stream* will send a `startBatch` message to the other\nside of [every connection](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/stream/impl/DefaultOutputStream.java#L139).\nHowever, the batch is not then immediately created. Instead, the other side of\nthe connection will wait to respond to the start message\n[until a message handler has actually been registered](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultConnectionInputBatch.java#L93)\nfor the batch. This creates a brief paused between the time the batch is created\nand the time the batch is started, but it also ensures that no messages can be\nsent on the batch until a handler is ready to receive them.\n\nBatches keep track of the number of groups that are created within them. When\na batch is ended, it will not actually send an `endBatch` message to the other\nside of the connection until all its child groups (if any) have been completed.\n\nWhen a group is created, each output stream [selects a single connection with\nits internal selector](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/stream/impl/DefaultOutputStream.java#L162).\nAs with batches, groups will not actually complete creation\n[until a message handler has actually be registered](https://github.com/kuujo/vertigo/blob/master/core/src/main/java/net/kuujo/vertigo/io/connection/impl/DefaultConnectionInputGroup.java#L90)\non the other side of the connection. And like batches, groups keep track of the\nchild groups created within them and cannot be successfully ended until all\nchild groups have been ended.\n\n**Need support? Check out the [Vertigo Google Group][google-group]**\n\n[vertigo-python]: https://github.com/kuujo/vertigo-python\n[vertigo-js]: https://github.com/kuujo/vertigo-js\n[google-group]: https://groups.google.com/forum/#!forum/vertx-vertigo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkuujo%2Fvertigo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkuujo%2Fvertigo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkuujo%2Fvertigo/lists"}