Skip to content

Implements RetryConnectionMiddleware for Oracle - #1303

Draft
DarkSide666 wants to merge 5 commits into
developfrom
feature/oracle-connection-retry
Draft

Implements RetryConnectionMiddleware for Oracle#1303
DarkSide666 wants to merge 5 commits into
developfrom
feature/oracle-connection-retry

Conversation

@DarkSide666

@DarkSide666 DarkSide666 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Implements RetryConnectionMiddleware and improve action workflow script for Oracle.

This fixes issue caused by Oracle listener which we also often see in Atk tests.
On heavier connection load Oracle randomly becomes inaccessible because Oracle listener have some delay before it actually drops connection out of its cache after you disconnect from db. As result listener kind of "overflows" and don't allow to make new connections to DB even if previous connections are all nicely closed and not hit DBs connection limit.

Implementation have no BC breaks as connection retries are done purely on background.

@DarkSide666 DarkSide666 self-assigned this Aug 14, 2026
/**
* Retries transient Oracle listener failures during connection establishment.
*
* Oracle may temporarily return ORA-12516 when the listener has not yet

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? IIRC this issue is present even with very few requests. What is the real connection count limit?

(and btw. this is already an issue with MySQL, but limit of small number of connections instead of strict 1 is enough and reliable)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current limits were:
Oracle-free (23) - 200 processes, 322 sessions
Oracle-xe (18) - 320 processes, 502 sessions

About 60-90 sessions can be already used internally by Oracle background services.

You can see more stats here https://github.com/atk4/data/actions/runs/31742995074/job/94590708915
Check steps Oracle stats before tests, Oracle stats after tests. These steps were added while testing and not included in this final PR. Also listener hitting limits is not visible in these stats because when listener hits limits, then it doesn't reach DB at all, so it's not visible in DB side of stats. It's only visible in listener log file, but it's stored on container which is not accessible from github job.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also you can check step "Stress test Oracle connections" in this job https://github.com/atk4/data/actions/runs/31723291851/job/94525337653
You can see there how it hits the limits randomly, then retries one or few times and then continue successfully.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proper solution might be to release the connection better. It might be even a bug in php driver.

Does this happen with pdo_oci as well as oci8?

A solution worth to consider might be even to force to release the connection using destructor.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a bug or something in php.
It's how Oracle Listener works. When you try to connect Oracle, then you first hit the listener and listener keeps track of active sessions too. If listener thinks that there are more active sessions than Oracle DB allows, then it do not pass you trough to database at all.
Listener has a tiny cache of that sessions stats and when you disconnect it doesn't instantly register that in its cache. So in very busy connect/disconnect load listener stays a bit behind.
Simple retrying in few quite small intervals is a way to go and solves everything.

{
return new class($driver) extends AbstractDriverMiddleware {
// ORA-12516: TNS:listener could not find available handler with matching protocol stack
private const RETRY_ERROR_CODES = [12516];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Discord you mentioned https://dbamarco.wordpress.com/2023/07/20/suspicous-ora-12516-by-oracle-scan-listener/ . I want to check if this desctribe the issue. In the chat, he wrote they increased the connection limit... Did you see this issue in production somewhen?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increasing connection limit is simplest workaround. Of course if you have 1000000 connections limit, then you'll not hit it while testing and all should be fine. But normally there shouldn't be such high limit. I've tested that all here in last few days. It's really that - in case of this failure just retry in 10-100ms (rarely a bit more - up till about 0.5s) and listener cache is updated, connections are freed and tests continue.
That wordpress topic is about slightly different kind of case, but still was the one to give me idea where to look at.

Comment thread .github/workflows/test-unit.yml Outdated
DB_USER: system
DB_PASSWORD: atk4_pass
# connection to portable database
DB_DSN: "pdo_oci:dbname=oracle/${{ matrix.type == 'Phpunit Lowest' && 'freepdb1' || 'xepdb1' }}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issues are mostly/solely present with "lowest". Ie. the lowest/oldest deps or the newest db. I would be happy to have this explained - is this because of the newest/never db and did some db limit changed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1303 (comment)
I think it's because oracle-fee (v23 which is used in lowest tests) have 322 sessions limit and 200 processes limit by default but old oracle xe has 502 and 320 respectively.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I trigged about 1000 pipelines with all Oracle versions and I have found:

  • the issue is present as you have written - with any many connections, no special query needed
  • the affected versions are >=23.4. With 23.3 or lower I was not able to trigger the issue at all

The retry solution might be the only one. I want to still do some more experiments.

Also, have the 322/502 200/320 limits changed with version 23.3 -> 23.4? If not, what changed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. That could be true about 23.3 and 23.4 as from 23.4 Oracle introduced AI Vector Search & Data Types - Version 23.4 officially introduced the native VECTOR data type and AI vector search features, which were not fully packaged or active in 23.3 developer builds.
Also they did Container and Setup Adjustments - Docker and container setup scripts (like network binding for tnsnames.ora) were updated and corrected in 23.4 compared to the 23.3 free/developer images.

I can't guarantee that this AI answer is correct, but that's approximately that.
image
image
image
image
image

But anyway, even if any of these solutions work, I still think that retry middleware is good to have as a fallback mechanism. No long retries, just try few times in quite short intervals and that's it.
It could be even helpful for other DB engines too to avoid some small sudden glitches while connecting.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot agree with the last paragraph. If 1 concurrent connection can exceed the total connections limit of 200, there is something very wrong with the database.

If there is a possibility of fixing this by some Oracle configuration, I might prefer it. I mean of course not by raising the concurrency to sky...

@DarkSide666 DarkSide666 Aug 21, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that would be perfect to fix it by Oracle settings of course.
But that doesn't mean that retry mechanism as such is a bad idea.
Normally you would not use Oracle as DB for busy webpages which does connect/disconnect all the time. Then Mysql or even Postgre is much better choice. Oracles power is more in data consistency, complex data cases, large data amounts etc. Also preferably by using persistent connections or connection pool at least.

P.S. Also Oracle uses like maybe 50 connections internally for its own services. So it's not 200 free connections at a start.

@DarkSide666
DarkSide666 requested a review from mvorisek August 15, 2026 10:57
@DarkSide666
DarkSide666 marked this pull request as draft August 16, 2026 19:13
@DarkSide666
DarkSide666 marked this pull request as ready for review August 16, 2026 19:43
Comment thread .github/workflows/test-unit.yml Outdated
APP_USER: atk4_test_user
APP_USER_PASSWORD: atk4_user_pass
# Provide healthcheck script options for startup
options: >-

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Github CI is dummy, all services are started one by one and all healtchecks are busy waited before tests. If a service starts slow, it will slowdown the CI.

Thanks and I will check this on the separate PRs. In past, I opted out for the healtchecks as the tests on other DBs were realiably enough without having to busy wait.

Please do not merge this PR yet, I want to land the other changes first and verify if retry mechanism is the only solution, I personally do not like it but on the other side Oracle is very ugly software and it might be the best working solution.

@atk4 atk4 deleted a comment from DarkSide666 Aug 17, 2026
@atk4 atk4 deleted a comment from DarkSide666 Aug 17, 2026
@atk4 atk4 deleted a comment from DarkSide666 Aug 17, 2026
@atk4 atk4 deleted a comment from DarkSide666 Aug 17, 2026
@atk4 atk4 deleted a comment from DarkSide666 Aug 17, 2026
@mvorisek
mvorisek marked this pull request as draft August 17, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants