Embedded RabbitMQ
Compatibility:
Builds: Linux OS X Windows
Reports:
Dist:
Social:
This library allows for the use of various RabbitMQ versions as if it was an embedded service that can be controlled from within the JVM.
The way it works is by downloading, from official repositories, the correct artifact for the given version and operating system, extracting it and starting the RabbitMQ Server with the specified configuration. The broker can then be administered from within the JVM by using equivalent commands to rabbitmqctl
or rabbitmq-plugins
.
Pre-requisites:
- This project requires Java 7+
- RabbitMQ Broker requires Erlang to be installed.
Quick Start:
1. Add a dependency to this project
For Maven:
<dependency>
<groupId>io.arivera.oss</groupId>
<artifactId>embedded-rabbitmq</artifactId>
<version>X.Y.Z</version>
</dependency>
For Ivy: <dependency org="io.arivera.oss" name="embedded-rabbitmq" rev="X.Y.Z" />
For Gradle: compile 'io.arivera.oss:embedded-rabbitmq:X.Y.Z'
For SBT: libraryDependencies += "io.arivera.oss" % "embedded-rabbitmq" % "X.Y.Z"
X.Y.Z
is the latest released version of this project. For more info visit Maven Central repo or visit the releases page.
For SNAPSHOT
releases, add the SonaType repository to your build system: https://oss.sonatype.org/content/repositories/snapshots/
2. Start the RabbitMQ broker
EmbeddedRabbitMqConfig config = new EmbeddedRabbitMqConfig.Builder().build();
EmbeddedRabbitMq rabbitMq = new EmbeddedRabbitMq(config);
rabbitMq.start();
When start()
is invoked, the Embedded-RabbitMQ library will download the latest release from RabbitMQ.com that best matches your Operating System. The artifact will be decompressed into a temporary folder, and a new OS process will launch the RabbitMQ broker.
Read more about how to customize your RabbitMQ broker.
3. Verify RabbitMQ is working as you'd expect
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = connectionFactory.newConnection();
assertThat(connection.isOpen(), equalTo(true));
Channel channel = connection.createChannel();
assertThat(channel.isOpen(), equalTo(true));
channel.close();
connection.close();
4. Stop the RabbitMQ broker:
rabbitMq.stop();
Customization
Customization is done through the EmbeddedRabbitMqConfig
and it's Builder
class. All snippets below will refer to this:
EmbeddedRabbitMqConfig.Builder configBuilder = new EmbeddedRabbitMqConfig.Builder();
...
EmbeddedRabbitMqConfig config = configBuilder.build();
EmbeddedRabbitMq rabbitMq = new EmbeddedRabbitMq(config);
rabbitMq.start();
Define a RabbitMQ version to use:
configBuilder.version(PredefinedVersion.LATEST)
or
configBuilder.version(PredefinedVersion.V3_6_5)
By using the version()
method, the download URL, executable paths, etc. will be pre-set for Unix/Mac/Windows Operating Systems. You can change the download source from the official rabbitmq.com
servers and Github by using the downloadFrom()
method:
configBuilder.downloadFrom(OfficialArtifactRepository.GITHUB)
Similarly, if you wish to download another version and/or use another server by specifying a URL:
String url = "https://github.com/rabbitmq/rabbitmq-server/releases/download/rabbitmq_v3_6_6_milestone1/rabbitmq-server-mac-standalone-3.6.5.901.tar.xz";
configBuilder.downloadFrom(new URL(url), "rabbitmq_server-3.6.5.901")
or if you are okay with the existing artifact repositories but you just need a released version not listed in the PredefinedVersion
enum:
configBuilder.version(new BaseVersion("3.8.1"))
Downloaded files:
By default, EmbeddedRabbitMq will attempt to save downloaded files to ~/.embeddedrabbitmq
. You can change this by making use of the downloadTarget()
setter, which accepts both a directory or a file:
configBuilder.downloadTarget(new File("/tmp/rabbitmq.tar.xz"))
...
// configBuilder.downloadTarget(new File("/tmp"))
Warning: If a file with the same name already exists, it will be overwritten.
The default behavior of this library is to re-use previously downloaded files. If you don't wish to use that behavior, disable it:
configBuilder.useCachedDownload(false)
To ensure a corrupted or partially downloaded file isn't re-used, the default behavior is to delete it when the issue is detected. This means that a fresh copy is downloaded next time. To disable this behavior do:
configBuilder.deleteDownloadedFileOnErrors(false)
Extraction path:
EmbeddedRabbitMq will decompress the downloaded file to a temporary folder. You can specify your own folder like so:
configBuilder.extractionFolder(new File("/rabbits/"))
Warning: The content of this folder will be overwritten every time by the newly extracted files/folders.
Advanced RabbitMQ management
If you wish to control your RabbitMQ broker further, you can execute any of the commands available to you in the /bin
directory, like so:
RabbitMqCommand command = new RabbitMqCommand(config, "command", "arg1", "arg2", ...);
StartedProcess process = command.call();
ProcessResult result = process.getFuture().get();
boolean success = result.getExitValue() == 0;
if (success) {
doSomething(result.getOutput());
}
where:
command
is something like"rabbitmq-ctl"
(no need for.bat
extension in Windows since it will be automatically appended).args
is a variable-length array list, where each element is a word (eg."-n", "nodeName", "list_users"
)
See the JavaDocs for more information on RabbitMqCommand
and other helper classes like RabbitMqDiagnostics
, RabbitMqCtl
, RabbitMqPlugins
and RabbitMqServer
which aim at making it easier to execute common commands.
Enabling RabbitMQ Plugins:
To enable a plugin like rabbitmq_management
, you can use the RabbitMqPlugins
class like so:
RabbitMqPlugins rabbitMqPlugins = new RabbitMqPlugins(config);
rabbitMqPlugins.enable("rabbitmq_management");
This call will block until the command is completed.
You can verify by executing the list()
method:
Map<String, Plugin> plugins = rabbitMqPlugins.list();
Plugin plugin = plugins.get("rabbitmq_management");
assertThat(plugin, is(notNullValue()));
assertThat(plugin.getState(), hasItem(Plugin.State.ENABLED_EXPLICITLY));
assertThat(plugin.getState(), hasItem(Plugin.State.RUNNING));
You can also see which other plugins where enabled implicitly, by calling the groupedList()
:
Map<Plugin.State, Set<Plugin>> groupedPlugins = rabbitMqPlugins.groupedList();
Set<Plugin> plugins = groupedPlugins.get(Plugin.State.ENABLED_IMPLICITLY);
assertThat(plugins.size(), is(not(equalTo(0))));
FAQ:
Troubleshooting:
Q: RabbitMQ fails to start due to ERROR: node with name "rabbit" already running on "localhost"
. Why is this and what can I do?
A: This happens when RabbitMQ fails to be stopped correctly in a previous run. To resolve this issue, manually identify the process and terminate it. To avoid this from happening again, ensure the stop()
method is invoked in your code.
Q: RabbitMQ fails to start with a message erl command not found
. What's this about?
A: RabbitMQ requires an installation of Erlang to be present in the system. Please install it first.
Q: RabbitMQ fails to start with a message {"init terminating in do_boot",{undef,[{rabbit_prelaunch,start,[]},{init,start_it,1},{init,start_em,1}]}}
A: Most likely you don't have an updated version of Erlang installed.
To check the version of Erlang in your system execute:
$ erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell
RabbitMQ requires:
- RabbitMQ v3.5.X requires Erlang
R13B03
at a minimum. - RabbitMQ v3.6.X requires Erlang
R16B03
at a minimum (or17
if you're using SSL/TLS).
For example, if your version is R14B04
, you can run RabbitMQ v3.5.X but not 3.6.X.
Read more here: http://www.rabbitmq.com/which-erlang.html
Acknowledgements
This project was inspired from other excellent Open Source libraries, particularly Embedded-MongoDB and Embedded-Redis.
Big thanks to the following OSS projects that made this project possible:
- Apache Commons Compress (and Tukaani's XZ utils) for extraction of compressed files.
- Zero Turnaround's Exec framework for execution of native OS processes.
- SLF4J API as a logging facade.
And of course, the biggest thanks to Pivotal and the RabbitMQ team for their hard work.
License
This project is released under Apache License Version 2.0, which basically means:
You can do what you like with the software, as long as you include the required notices. This permissive license contains a patent license from the contributors of the code.
Summary courtesy of: https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
Say thanks
If you want to say thanks, you can:
- Star this project
- Donate:
- Contribute improvements