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 The Erlangelist - 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: [erlang-questions] How do you kill an OS process that was opened with open_port on a brutal_kill?, 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.

Last Post!

why

why

Thanks a ton @mindok :slight_smile:

Very much appreciate it!

Where Next?

Popular in Questions Top

Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
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
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
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
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
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...
3271 130579 1222
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
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

We're in Beta

About us Mission Statement