Subject: [pgjdbc/pgjdbc] PR #3964: Allow setting of KeepAlive options in JDBC driver

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Sun, 15 Mar 2026 17:09:07 +0000

Fix #2487 

Adds `tcpKeepCount`, `tcpKeepIdle`, and  `tcpKeepInterval` PG properties. These properties allow to fine tune `tcpKeepAlive`.

I am willing to write automated tests for this. But I didn't find any test related to `PGProperty#TCP_KEEP_ALIVE`. If tests are needed, please give me some pointers about how to test these new options.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 08:38:55 +0000

Sorry for all the noise, `convert to draft` action is not working :man_shrugging:

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Mon, 16 Mar 2026 08:41:37 +0000

There are two ways to test the new options:
1) Add them to the matrix. Check out https://github.com/pgjdbc/pgjdbc/commit/bd572f408b315aa91739a60e58c2413770c054cd as an example
2) There might be a targeted test for the new option. I'm not sure what could be the way to ensure the settings work as intended.

By the way, do the new settings apply without explicit `SO_KEEPALIVE` activation?

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Mon, 16 Mar 2026 08:47:11 +0000

(on pgjdbc/src/main/java11/org/postgresql/core/ExtendedSocketOptionAccessorImpl.java:89)

Can this be a direct class reference?
I guess it should compile with `--release 11`, so `jdk.net.ExtendedSocketOptions.class` should work here.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 08:53:56 +0000

That's what I wanted to do first. But https://github.com/policeman-tools/forbidden-apis made the build fail when I tried.

That's because components of root package `jdk` are not guaranteed to be available in every JDK. See https://docs.oracle.com/en/java/javase/11/docs/api/index.html about JDK:
> The Java Development Kit (JDK) APIs are specific to the JDK and will not necessarily be available in all implementations of the Java SE Platform.

Therefore, unless you want to relax the constraint, I think reflection is needed.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Mon, 16 Mar 2026 08:59:40 +0000

We use the APIs only for the specific socket options, so I'm gravitating to going with direct `ExtendedSocketOptions.FIELD_NAME` usages and just let it fail in the runtime if the JDK misses the option.
We could probably skip the class from forbidden-apis check.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 09:04:24 +0000

Ok, I will do that.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 09:06:21 +0000

> 1. Add them to the matrix. Check out [bd572f4](https://github.com/pgjdbc/pgjdbc/commit/bd572f408b315aa91739a60e58c2413770c054cd) as an example

I don't know if you saw it, I added conditional assertions to `ConnectionTest#pGStreamSettings`.

> By the way, do the new settings apply without explicit `SO_KEEPALIVE` activation?

I didn't find any explicit hint about this in the JDK documentation. Because of that, I didn't want to make any assumption neither in the code nor in this project's documentation.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 09:10:28 +0000

But this causes an issue. How to copy socket options in `PGStream` ( https://github.com/pgjdbc/pgjdbc/pull/3964/changes#diff-1c9bbe3aa0c1f2d0d7a6ecef10d981c2be064a526e8f91e2b47b04823fd50dedR160-R162 ) without failure? At this step, we don't know if `ExtendedSocketOptions` have been explicitly required by the library consumer.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 16 Mar 2026 09:30:49 +0000

In addition to `ConnectionTest#pGStreamSettings` new assertions, I added `ConnectionTest#socketSettings`. If I understand correctly, `ConnectionTest` will be executed on multiple JDK versions including versions above 11. Therefore, I don't think there is a need to manipulate the matrix configuration. But please tell me if I am wrong.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Tue, 17 Mar 2026 13:53:57 +0000

@vlsi , I don't think the appveyor failure is caused by my change.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Tue, 17 Mar 2026 14:19:22 +0000

We plan to drop appveyor soon (see https://github.com/pgjdbc/pgjdbc/pull/3966), so please don't pay attention to it

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Tue, 17 Mar 2026 14:25:13 +0000

> I don't know if you saw it, I added conditional assertions to ConnectionTest#pGStreamSettings.

It is fine to add assertions to `ConnectionTest`, however, we'd better ensure all the tests are runnable with `keepalive` on, so I would still like to add keepalive to the matrix.

In fact, we could even configure non-default values for the newly added settings for the recent JDKs we have in our matrix.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Tue, 17 Mar 2026 17:14:18 +0000

@vlsi , I added a `keep_alive` axis to the matrix.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Tue, 17 Mar 2026 17:23:01 +0000

(on README.md:94)

Please refrain from reformatting the table for adding a couple of rows only

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Tue, 17 Mar 2026 17:38:53 +0000

(on README.md:94)

Sorry, I think I slipped on the reformat shortcut of my IDE :)
I reverted the formatting.

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Tue, 17 Mar 2026 18:18:35 +0000

@vlsi , do you think the CI failure is caused by my change?

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Tue, 17 Mar 2026 18:51:19 +0000

Looks like the change is not related

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Tue, 17 Mar 2026 19:38:29 +0000

Should we mark this one as resolved or do you have a suggestion?

---

From: "gitguardian[bot] (bot) (@gitguardian[bot])" <noreply+gitguardian[bot]@github.com>
Date: Thu, 19 Mar 2026 08:33:29 +0000

#### ⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

<details>
<summary>🔎 Detected hardcoded secret in your pull request</summary>
<br>

| GitGuardian id | GitGuardian status | Secret                         | Commit           | Filename        |                      |
| -------------- | ------------------ | ------------------------------ | ---------------- | --------------- | -------------------- |
| [28941571](https://dashboard.gitguardian.com/workspace/59849/incidents/28941571) | Triggered | Generic Password | 97dd40b30679e1da248169f086cf91240d925370 | .github/workflows/main.yml | [View secret](https://github.com/pgjdbc/pgjdbc/commit/97dd40b30679e1da248169f086cf91240d925370#diff-7829468e86c1cc5d5133195b5cb48e1ff6c75e3e9203777f6b2e379d9e4882b3R290) |

</details>

<details>
<summary>🛠 Guidelines to remediate hardcoded secrets</summary>
<br>

1. Understand the implications of revoking this secret by investigating where it is used in your code.
2. Replace and store your secret safely. [Learn here](https://blog.gitguardian.com/secrets-api-management?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) the best practices.
3. Revoke and [rotate this secret](https://docs.gitguardian.com/secrets-detection/secrets-detection-engine/detectors/generics/generic_password#revoke-the-secret?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment).
4. If possible, [rewrite git history](https://blog.gitguardian.com/rewriting-git-history-cheatsheet?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment). Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider

-   following these [best practices](https://blog.gitguardian.com/secrets-api-management/?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) for managing and storing secrets including API keys and other credentials
-   install [secret detection on pre-commit](https://docs.gitguardian.com/ggshield-docs/integrations/git-hooks/pre-commit?utm_source=product&amp;utm_medium=GitHub_checks&amp;utm_campaign=check_run_comment) to catch secret before it leaves your machine and ease remediation.

</details>

---

<sup>🦉 [GitGuardian](https://dashboard.gitguardian.com/auth/login/?utm_medium=checkruns&amp;utm_source=github&amp;utm_campaign=cr1) detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.<br/></sup>

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Thu, 19 Mar 2026 16:09:41 +0000

@vlsi I guess this failure is also caused by flakiness?

> Java 8, corretto, PG 17, scram, ssl, windows, server_tz America/New_York, client_tz America/New_York, fr_FR, no_gss, replication, slow_tests, adaptive_fetch, rewrite_batch_inserts, query_timeout 15, autosave conservative, cleanupSavepoints

```
org.postgresql.replication.LogicalReplicationTest > replicationRestartFromLastFeedbackPositionParallelTransaction() failure marker
  Error:   0,6sec org.postgresql.replication.LogicalReplicationTest > replicationRestartFromLastFeedbackPositionParallelTransaction()
  java.lang.AssertionError: When we add feedback about applied lsn to replication stream(in this case it's force update status)after restart consume changes via this slot should be started from last success lsn that we send before via force status update, that why we wait consume both transaction without duplicates
  Expected: "BEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT\nBEGIN\ntable public.test_logic_table: INSERT: pk[integer]:2 name[character varying]:'second tx changes'\nCOMMIT"
       but: was "BEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT\nBEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT"
      at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
      at org.postgresql.replication.LogicalReplicationTest.replicationRestartFromLastFeedbackPositionParallelTransaction(LogicalReplicationTest.java:839)
FAILURE   0,6sec, org.postgresql.replication.LogicalReplicationTest > replicationRestartFromLastFeedbackPositionParallelTransaction()
    java.lang.AssertionError: When we add feedback about applied lsn to replication stream(in this case it's force update status)after restart consume changes via this slot should be started from last success lsn that we send before via force status update, that why we wait consume both transaction without duplicates
    Expected: "BEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT\nBEGIN\ntable public.test_logic_table: INSERT: pk[integer]:2 name[character varying]:'second tx changes'\nCOMMIT"
         but: was "BEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT\nBEGIN\ntable public.test_logic_table: INSERT: pk[integer]:1 name[character varying]:'first tx changes'\nCOMMIT"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.postgresql.replication.LogicalReplicationTest.replicationRestartFromLastFeedbackPositionParallelTransaction(LogicalReplicationTest.java:839)
```

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Fri, 20 Mar 2026 10:46:39 +0000

Marking it as resolved. But open to suggestions :)

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Mon, 23 Mar 2026 21:31:14 +0000

Hi @vlsi ,
Are you expecting an action from me?

---

From: "reda-alaoui (@reda-alaoui)" <[email-masked]>
Date: Sun, 26 Apr 2026 20:02:42 +0000

@vlsi anything I should do to get this merged? :)