Skip to content

Create server launcher to replace mcserver #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
3 tasks
tonygermano opened this issue Mar 29, 2025 · 10 comments · May be fixed by #61
Open
3 tasks

Create server launcher to replace mcserver #2

tonygermano opened this issue Mar 29, 2025 · 10 comments · May be fixed by #61
Assignees

Comments

@tonygermano
Copy link
Member

tonygermano commented Mar 29, 2025

mcserver was created by install4j, and the configuration was not open source. I don't believe that a replacement for mcservice is required, as each platform has a preferred way to run a service, and they should all work with a simple launcher.

needs:

  • a binary or script that can run with a double-click (source code must be open)
  • must process a .vmoptions file as described here or something similar in a different documented format.
    • in addition to directly using options as arguments to the java executable, it supports special values for:
      • replacing, appending to, or prepending to the classpath
      • including other vmoptions files, with environment variable substitution in the path
  • ensure that the classpath is built in the correct order. Certain project libraries reimplement classes from other libraries and must come earlier on the classpath.
  • able to locate a jvm with which to launch the server

nice-to-haves:

  • easy (and well documented) way to configure it to launch using a specified jvm. Shouldn't require a system-wide jvm to be installed.
  • detect java version and automatically include known required options for java 9+

Platform support (check as completed):

  • Windows
  • macOS
  • Linux (+docker)
@ssrowe
Copy link

ssrowe commented Mar 31, 2025

I think this may be 2 separate issues.

  1. Server launcher/Daemon
  2. Setup/install

For the daemon, Apache Commons Daemon might be a good choice. It appears widely used, small overhead, with cross-platform capability and native integrations for both Windows and *nix.
https://commons.apache.org/proper/commons-daemon/index.html

For the setup, jpackage appears to be officially supported from OpenJDK 16. While it appears rudimentary, it does have native support for Windows and *nix.
https://openjdk.org/jeps/392

@kpalang
Copy link
Contributor

kpalang commented Apr 2, 2025

easy (and well documented) way to configure it to launch using a specified jvm. Shouldn't require a system-wide jvm to be installed

We could look into using the distributions backend used by SDKMAN to choose a JVM.

@tonygermano
Copy link
Member Author

I think this may be 2 separate issues.

  1. Server launcher/Daemon
  2. Setup/install

I think those are actually 3 issues.

  1. Server launcher (wrapper around java binary to run in foreground)
  2. Server Daemon (daemonize launcher)
  3. Setup/install

I intended for this issue to only cover the first of those 3.

We could look into using the distributions backend used by SDKMAN to choose a JVM.

Personally, I'd prefer good documentation over trying to do too much.

I.e., in the setup guide:

- Do XXXX to specify the location of your preferred java runtime
- If you need help choosing or downloading a java runtime, see <link to other help article>

Down the road if we want to include a separate tool to assist with acquiring a java runtime, I think that's a separate feature request. In the near term, using SDKMAN itself could be one of the suggestions in the help article.

@ssrowe
Copy link

ssrowe commented Apr 3, 2025

@tonygermano can you explain why you'd want/need a wrapper to run in the foreground? and why that should be different than the daemon launcher? i look at the engine as something that should only be ran as a service - os, docker, whatever. and running in the foreground is simply a feature used for troubleshooting.

a binary or script that can run with a double-click (source code must be open)

can you elaborate on this? i assumed this meant an installer.

@tonygermano
Copy link
Member Author

@ssrowe I'm using mirth lingo here as it exists in 4.5.2.

Mirth has always offered two ways to start the server, mcserver and mcservice. mcserver runs in the foreground and logs information to the console. Sometimes it provides additional information than what makes it into mirth.log. mcservice starts a daemonized process and lets you manage it with stop/start/status commands, but in most cases, you still want to rely on an OS level service manager to manage the process instead.

In modern systems, mcserver should be the preferred way to start the server. For development purposes, you likely want to be running in the foreground. Docker prefers that the main process runs in the foreground. This also allows it to capture sysout to make it available when running docker logs. Systemd prefers services that run in the foreground, which allows it to manage starting and stopping processes itself rather than outsourcing that to a different application. Running in the foreground will also let systemd collect logs in a standard way.

I am proposing that for this issue we only recreate mcserver. A separate issue would be creating the OS specific methods for creating a service to run the launcher. Windows is the only OS that really presents any difficulty with that piece.

Docker shouldn't use a daemon process because you typically would not want to launch a background process inside the container that you need to manage. If you want to stop the server, you should just need to stop the container and not need to mess around inside of it. To further that point, the NextGen docker containers run mcserver, not mcservice.

Systemd only requires a .service unit file to create a service on Linux systems. This has already been shown to work with mcserver through multiple forum posts/slack discussions. I'm not as familiar with mac, but the launchd .plist files look very similar to how systemd works.

@ssrowe
Copy link

ssrowe commented Apr 18, 2025

@tonygermano i think we’re saying essentially the same thing. The “double-click” thing threw me off.

i agree we only need a server component that runs in the foreground and that is ran from the CLI interactively or from systemd, docker, or similar. Essentially a bootstrapper.

while Windows is more unique, there appears to be some differences between other platforms as well. with a very simple interface, we can leverage the Apache Commons Daemon (don’t let the name confuse things). It’s simple a set of platform native binaries that give us more control over class loading and config than a shell scripts which diff between platforms. It does have some overlap with systemd, that we can simply ignore.

this appears to be battle-tested code that would allow us to simplify things. Thoughts?

@mgaffigan
Copy link
Contributor

mgaffigan commented May 27, 2025

I made a crack parsing vmoptions in bash in #101 which I expect might apply for *nix platforms. I'm of the opinion that any non-trivial server app should be running in a container, these days, but assuming the bash version is acceptable I'm happy to produce a windows equivalent that runs as an NT Service. Systemd, too.

Beyond whether the quick-and-dirty vmoptions support is sufficient, I'd need clarification re:

  • Where classpath should come from and what the correct order is, since I did not see it in reimplementation of mirth-connect.sh
  • What JVMs are "supported" and differentiated options (seems like mcservice-java9+.vmoptions is no more)

@tonygermano
Copy link
Member Author

I made a crack parsing vmoptions in bash in #101 which I expect might apply for *nix platforms. I'm of the opinion that any non-trivial server app should be running in a container, these days, but assuming the bash version is acceptable I'm happy to produce a windows equivalent that runs as an NT Service. Systemd, too.

Beyond whether the quick-and-dirty vmoptions support is sufficient, I'd need clarification re:

@mgaffigan I have already created a clojure program that does what I intended when I opened this issue, but I do not like how it needs to be deployed and run. See #61

I was thinking about rewriting it in Go as that should not be difficult to do, and it should then more easily compile to platform native executables. My priorities needed to shift elsewhere before I could get around to doing that, and we are using install4j in the near-term to be able to get a release out for people to be able to install and test the application.

An alternative that I considered was rather than having a tool that launched java as a child process, it could just generate and return the full command to start java with the appropriate args after processing the vmoptions files. Then the output could be executed by a shell or used to create a service.

One of the things I really like that I added, and which is not supported by install4j, is the -java-cmd directive which lets you point to a specific JRE in the vmoptions file, so it's very easy to switch between specific java version when the user has multiple versions available, whether they are installed system-wide or not.

The other things I implemented with environment variable substitution, recursive includes, and classpath manipulation are all described here https://www.ej-technologies.com/resources/install4j/help/doc/concepts/vmParameters.html

  • Where classpath should come from and what the correct order is, since I did not see it in reimplementation of mirth-connect.sh

The only thing that must be on the classpath at this time is mirth-server-launcher.jar. It brings in a few more requirements via its manifest, and the rest is all loaded dynamically during runtime. However, the user should be able to specify additions to the classpath if necessary (which can be done by special directives in the .vmoptions files.)

  • What JVMs are "supported" and differentiated options (seems like mcservice-java9+.vmoptions is no more)

It was moved to /conf/default_modules.vmoptions and is currently included by /oieserver.vmoptions or /oieservice.vmoptions. I'm 90% sure that java 17 will be the minimum "supported" java version, even though we still build with java 8 for right now.

@mgaffigan
Copy link
Contributor

mgaffigan commented Jun 11, 2025

Thanks for the clarification, @tonygermano. Here's my understanding to confirm:

  • TP1 is expected to use Install4J for all launch scripts
  • Expected deployment scenarios for mirth-server include
    • Linux via systemd / interactive
    • Mac OS X via launchd / interactive
    • Containerization via interactive
    • Windows via NT Services
  • The standard mirth-server classpath is only mirth-server-launcher.jar, but .vmoptions files should allow extension via -classpath/-classpath/a/-classpath/p
  • The standard mirth-server vm args are in server/basedir-includes/oieserver.vmoptions
  • vmoptions files may include other vmoptions files using -include-options
  • It is desirable to extend the vmoptions syntax to override the path to java through a -java-cmd keyword
  • The vmoptions environment variable syntax should be retained

From this, bash seems sufficient for Linux/Mac/Docker. I translated the Clojure to Python for my own sake, but was able to minimally edit the bash script I put together previously to meet the above requirements. I was able to simplify things a bit by execl-ing into the new process, rather than creating a subprocess.

Windows requires something dedicated given the NT Service interaction. If you are using Install4J for the windows installer, I would presume that would also be used for the NT Service. If you want to avoid Install4J for windows, then Wix + a small C# program would be easiest.

Thoughts?

@mgaffigan
Copy link
Contributor

mgaffigan commented Jun 11, 2025

Thinking a bit further on this, is anyone running production servers on Mac OS? I understand using servers running on Mac OS for development and test - but is start-at-boot actually a requirement when OS X Server is out-of-support for at least three years?

Theoretical deployment story::

OS Server Deployment Client Launcher Deployment
Linux tgz / oci container / apk+systemd / rpm+systemd tgz / apk / rpm
Mac OS X pkg (optional) dmg
Windows msi (optional) msi

In all cases, the client would be installed by the platform's typical means. Working through the use cases:

  • The container shop
    Any shop with other docker or k8s apps are pushed towards server deployment via docker. Getting started: docker run openintegrationengine/engine:latest
  • The graybeards
    Server and launch manifest is distributed via apt/yum. Getting started: apt install openintegrationengine
  • The Mac OS Curious
    Downloads the Mac OS client launcher DMG. Default option is to start a mirth server on connect. Server runs in the user's session, and appears in the menu bar.
  • The Mac OS interface engineer
    Downloads the Mac OS client launcher DMG. Connects to a server running on another server, in container, or added to launchd with scripts.
  • The Windows interface engineer
    Downloads the Windows client launcher msi. Connects to a server installed elsewhere.
  • The Windows Curious
    Downloads the Windows client launcher msi. Default option is to start a mirth server on connect, Server runs in the user session, and appears in the notification area.
  • The Windows shop
    Downloads the Windows server msi. Server is installed with small wrapper as NT Service. No client is installed.
    Downloads the Windows client msi. Connects to the NT Service install.
  • The "you can have my XServe when you pry it from my cold dead hands"?
    Downloads the Mac OS X server pkg. Server is installed in launchd. No client is installeed.
    Downloads the client dmg. Connects to the launchd initiated server.

With super users having the escape hatch of compiling from source easily, or from doing something magic off of tgz artifacts.

The above does presuppose that we can merge in-tree a client launcher, but I think all of this would be pretty clean: clean build pipeline, clean deployment story without signing secrets, and most importantly a clean onboarding for a mirth naïve user.

While this would be a departure from the historical deployment pattern, I think the changes to deliver this would be relatively achievable:

  • Add OCI artifacts for containerized deployment
  • Add APK/RPM packaging scripts and artifacts
  • Add OS X launcher and DMG artifact
  • Add Windows NT Service wrapper and service installer artifact
  • Add Windows launcher and installer artifact

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants