mindok

mindok

Killing java processes started from Port.open

Hi all, my current work involves interacting with MS Project files. The binary file format is pretty tedious to interact with. The best third party library I have found for reading the files is written in Java.

I have written a small test Java project that I have interoperating with a test Elixir project following guidance from this post https://www.theerlangelist.com/article/outside_elixir from @sasajuric.

The only problem is that the java program doesn’t die when the owning BEAM process dies or BEAM is terminated. This is discussed here: http://erlang.org/pipermail/erlang-questions/2016-November/090910.html, and it sounds like it all relies on the program invoked by Port.open being “well-behaved” and shutting down if the stdin channel is killed.

I have trawled the Java docs and aside from realising how convoluted the process is for writing anything useful in Java (compared with Elixir), I haven’t found anything to help.

So the questions are:

  1. has anyone managed to get a well-behaved interop between Java and Elixir using Ports.
  2. If so, what does your main System.in reading code look like / how did you solve the problem of shutting down the java program without explicit termination commands from the Elixir side
  3. If not, what are the preferred options for Java interop. I am aware of JInterface but wanted to keep operational complexity down as far as possible and also minimise the amount of Java code.

I know this is probably a Java problem rather than an Elixir problem, but the Ports style interop for long-running processes through stdin/stdout does seem to be unique to Erlang/Elixir.

Edit: Only tries on Windows so far. Will year on Linux tomorrow.

Thanks!

Marked As Solved

sasajuric

sasajuric

Author of Elixir In Action

Yes, if you want proper cleanup, the external program has to be well-behaved. I’ve briefly touched on that in the article, in the “program termination” section. So basically, you need to make the Java program terminate if you receive EOF on stdin. No idea how this can be done in Java, but I’d be surprised if this wasn’t possible :slight_smile:

If you don’t control the external program, you could use erlport, which will automatically terminate the external program if the owner beam process (or the entire beam node) stops.

Also Liked

jayjun

jayjun

Creator of Rambo here. Don’t use libraries if you’re writing your own port. Libraries are for working around external programs that cannot be changed.

Your minimal program is a good start, just need to read (block on) standard input on another thread so your MS Project job can run.

If you don’t care about JVM startup time, just run your port with System.cmd on demand. Otherwise if your Java process is long-lived, you’ll need to consider the communication protocol between your Java and Erlang processes.

mindok

mindok

OK, problem exists between chair & keyboard. My main loop was badly behaved. I stripped it back to the most basic stdin read loop and it terminates ok. Time to start building it up again and see where it fails.

For reference, here’s a minimal Java program that works nicely over ports, terminating when the process or BEAM terminates (including brutally killing from Windows task manager):

package com.thing;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        int ch;
        while(true) {
            ch = System.in.read();
            if (ch == -1) {break;} // This is the EOF signal in Java
            if (ch == 'q') {break;}
            if (ch == 't') {System.out.println("tasks");}
            System.out.println(" got " + ch + " - " + (char)ch);
        }
    }
}
jayjun

jayjun

Thanks for the mention. To clarify, Rambo only requires the Rust compiler if you are not using Linux, macOS or Windows. Bundled binaries should cover most users.

NobbZ

NobbZ

Besides of the already mentioned erlport there are a couple of other projects available, like porcelain which relies on a wrapper written in Golang, which has to be installed seperately, or rambo which explicitely not only manages the lifecycle of the program, but also is able to wrap those programs that do only print their own reply after stdin got closed. Its wrapper is written in Rust, and as far as I remember you need to have rust installed to compile the library.

mindok

mindok

Thanks @jayjun - yes, the java process will be long lived. I’ve worked up a more extended example that uses Erlang ETF to transmit the payload back and forth. The Ericsson JInterface library has all the parsing and packaging routines. There are a couple of gotchas that I’ll write up (eg the OtpOutputStream doesn’t write the first byte - 131 - for some reason so you have to do that by hand), but it seems pretty straightforward otherwise. The Java side can respond synchronously to each call in my case which simplifies things on that side.

Where Next?

Popular in Questions Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New

We're in Beta

About us Mission Statement