Skip to content

PostgreSQL processes remain running after JabRef crashes or is forcefully terminated #12844

Open

Description

@ungerts

JabRef version

Latest development branch build (please note build date below)

Operating system

Windows

Details on version and operating system

Windows 10

Checked with the latest development build (copy version output from About dialog)

  • I made a backup of my libraries before testing the latest development version.
  • I have tested the latest development version and the problem persists

Steps to reproduce the behaviour

When JabRef crashes or is forcefully terminated (e.g., via kill -9 or Task Manager), associated PostgreSQL processes often remain running. These orphaned processes continue to consume system resources unnecessarily.

Steps to Reproduce

  1. Start JabRef with a PostgreSQL backend.
  2. Forcefully terminate JabRef (e.g., using kill -9 or Task Manager).
  3. Open Task Manager (Windows) or use ps on Linux/macOS.
  4. Observe that multiple PostgreSQL Server processes are still running.

Expected Behavior

All PostgreSQL-related processes spawned by JabRef should terminate when JabRef is unexpectedly closed.

Actual Behavior

PostgreSQL processes persist after JabRef exits unexpectedly, leading to orphaned background processes.

Appendix

Screenshot

PostgreSQL orphaned processes

Screenshot shows several idle PostgreSQL Server processes still running after JabRef was terminated.

Activity

  1. added theissue type on Mar 28, 2025
  2. Siedlerchr commented on Mar 28, 2025

    @Siedlerchr
    Member

    Sigkill cannot be caught, but it would probably make sense to add a shutdown hook to ensure running instances are closed when sigterm occurs

  3. subhramit commented on Mar 28, 2025

    @subhramit
    Member

    I have faced this too (noticed this yesterday). Every time I close and re-run JabRef (when running via IntelliJ), my task manager shows the old Postgres instance running. On running a new JabRef session again, a new Postgres session is also launched. After 5-6 trials, I was wondering why my system was lagging so much, then checked the task manager which had 6 running postgres instances.

    Edit - what I meant was another implication of this is lag during development.

    Edit - more details:
    1st run: 1 background process, 6 instances:

    Image

    Second run using IntelliJ reload:

    Image

    Now there are 2 background processes, 12 instances:

    Image

    All of them on CPU 00:

    Image

    And so on...

  4. moved this from Normal priority to High priority in Prioritizationon Mar 28, 2025
  5. added this to the 6.0-beta milestone on Mar 28, 2025
  6. subhramit commented on Mar 28, 2025

    @subhramit
    Member

    Tried with:

    public class Launcher {
    
        public static void main(String[] args) {
           ...
    
            PostgreServer postgreServer = new PostgreServer();
            Injector.setModelOrService(PostgreServer.class, postgreServer);
            
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                if (postgreServer != null) {
                    try {
                        postgreServer.shutdown();
                        System.out.println("PostgreServer successfully shut down");
                    } catch (Exception e) {
                        System.err.println("Error shutting down PostgreServer: " + e.getMessage());
                    }
                }
            }));
    
            JabRefGUI.setup(uiCommands, preferences, fileUpdateMonitor);
            JabRefGUI.launch(JabRefGUI.class, args);
        }
    }

    Didn't work

  7. subhramit commented on Mar 28, 2025

    @subhramit
    Member

    Tried with:
    ...
    Didn't work

    On checking logs, neither the try nor the catch is executed. On reading more, it appears that it's because there is no way to reliably execute code in case of a SIGKILL (the shutdownhook helps in case of SIGTERM and SIGINT).

  8. Siedlerchr commented on Mar 28, 2025

    @Siedlerchr
    Member
  9. subhramit commented on Mar 28, 2025

    @subhramit
    Member

    Hmm...so is this issue unsolvable from the perspective of shutdown it seems..

  10. koppor commented on Mar 29, 2025

    @koppor
    Member

    Hmm...so is this issue unsolvable from the perspective of shutdown it seems..

    Idea for workaround: On start of new JabRef instance, old postgres (from JabRef) could be re-used (or killed)

  11. ungerts commented on Mar 29, 2025

    @ungerts
    ContributorAuthor

    Idea for workaround: On start of new JabRef instance, old postgres (from JabRef) could be re-used (or killed)

    To me, this feels a bit like performing "magic" on the user's machine. Implementing such behavior is likely to be complex and error-prone.

    • PostgreSQL ports are allocated automatically. As a result, the application would need to either:

      • Detect the port currently in use at runtime, or
      • Persist the assigned port on first launch and reuse it upon restart.
    • Multiple PostgreSQL instances might be running on the user's system:

      • Some could be installed manually by the user.
      • Others might be leftover (or orphaned) instances from previous JabRef sessions.

    This leads to a critical question: Which instance should JabRef attempt to reuse - or safely shut down?

  12. removed this from the 6.0-beta milestone on Mar 30, 2025
  13. 38 remaining items

  14. subhramit commented on Jan 5, 2026

    @subhramit
    Member

    I am thinking whether handling SIGKILL is something a software should (or can) make behavioral guarantees about, since control can no longer be in hands of it.

    For crashes - i think we should look at the reason. Only if caused due to something going wrong in jabref, we should fix that.
    For forceful termination - again, that is not an intended way to use JabRef.

    If there was a way to handle sigkill gracefully, we would. But until then, and in one perspective, this issue seems to be intended behavior.
    Reusing postgres instances should be a separate issue, and this IMO could be closed.
    @koppor we need to add to devdocs not to use the IntelliJ restart or IntelliJ "X" terminate button (instead of JabRef) during development as it can lead to postgres processes hogging memory. I'll add it.

  15. k3KAW8Pnf7mkmdSMPHz27 commented on Mar 2, 2026

    @k3KAW8Pnf7mkmdSMPHz27
    Member

    Status update: I did some local prototyping on this but am not pursuing it further — this is available for anyone interested.

    Context: The long-term fix may come from #12708 (GSoC project exploring replacing embedded Postgres with an in-process solution), which would eliminate orphan processes by design. However, this issue is worth fixing independently since the solution is straightforward and the problem affects users daily (see @subhramit's report above).

    The core challenge: SIGKILL cannot be caught by the JVM — shutdown hooks and AutoCloseable.close() never execute. Approaches explored in this thread:

    Approach Handles SIGKILL? Trade-off
    Pipe-EOF monitor — spawn a lightweight watchdog process connected to JabRef via stdin; kernel closes pipe on parent death → watchdog kills Postgres Yes, immediately Adds an extra OS process
    PID file + next-launch cleanup — write Postgres PID to disk, check/kill on next JabRef start No (delayed until next launch) Simple, no extra process, but stale instances linger
    JVM shutdown hook No (SIGTERM/System.exit only) Already provided by zonkyio; doesn't help with SIGKILL

    The pipe-EOF approach is the most robust — see @Siedlerchr's linked resources on signal handling and @subhramit's findings confirming shutdown hooks don't fire on SIGKILL.

    For anyone picking this up: The PID-file approach (suggested by @UdayHE) is the simplest starting point. The pipe-EOF monitor is more robust if you want immediate cleanup. Either would be a welcome improvement.

  16. subhramit commented on Mar 2, 2026

    @subhramit
    Member

    Pipe-EOF monitor — spawn a lightweight watchdog process connected to JabRef via stdin; kernel closes pipe on parent death → watchdog kills Postgres

    For whatever reason, this did not work on Windows.

    I also want to highlight that unless we someday decide to allow only one running JabRef instance, there may be cases of multiplicity between JabRef and Postgres processes that may need handling.

  17. subhramit commented on Jun 23, 2026

    @subhramit
    Member

    We received a proposal this year, summarized (via AI) below, that would mostly fix this:

    Proposed Action Plan

    1. Implement a Data Access Layer (DAL)

      • Design a DAL to replace direct in-memory BibDatabase usage.
      • Create a SQLite schema for bibliographic entries, metadata, and abbreviations.
      • Replace in-memory reads with SQLite-backed queries.
    2. Integrate Lucene search

      • Implement a custom analyzer for LaTeX → Unicode normalization.
      • Support substring, regex, and fuzzy search.
      • Unify search functionality around Lucene.
    3. Refactor the GUI to use the DAL

      • Update MainTable and related components to retrieve data through the DAL.
      • Add lazy loading/pagination to avoid loading entire libraries into memory.
    4. Maintain compatibility with existing workflows

      • Provide a migration layer so existing .bib-based workflows continue to function.
    5. Test and optimize

      • Benchmark query latency, indexing performance, index size, and reindexing time.
      • Add unit and integration tests.
      • Optimize indexing and synchronization between SQLite and Lucene.

    Expected Outcome

    Replace JabRef's current in-memory architecture with a hybrid SQLite (storage) + Lucene (search) backend that:

    • Removes RAM limitations for large libraries.
    • Enables scalable, disk-backed storage.
    • Improves search capabilities and performance.
    • Simplifies the architecture by avoiding external database processes.
    • Supports a fully database-backed GUI with lazy loading.

    Refs. #12708 (comment)

  18. koppor commented on Jun 23, 2026

    @koppor
    Member

    ADR and MWEs for the backends are done at JabRef#727

    MWEs really with a Docker image spawning Java programs and checking things. I thought, JBang would be a nice tool there ^^

  19. modified the milestones: 6.0, 6.1 on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    component: internal-storageJabRef's internal data handlilng (PostgreSQL, Lucene, ...)

    Type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions