Parallel long running irods jobs result in conflicting session refresh tokens. Thus, py4lexis is limited to 1 job that takes "longer" per user

I have several processes running in parallel, accessing IRODS via a single account. This works fine until a certain point in time, where the session times out >10h). After the timeout, it seems the refresh tokens are conflicting and disconnects irods session from Lexis sessions, producing and ExceptionOpenIDAuthUrl: https://aai.lexis.tech/auth/realms/LEXIS_AAI_v2/protocol

Conclusion / Evidence:

  • Based on my tests below, where two jobs run producing ExceptionOpenIDAuthUrl, starting a third process (my script below), that basically does something like:
lexis_session = LexisSession(suppress_print=False, in_cli=True,offline_access=True,login_method="url")
print(iRODS(session=lexis_session).get_dataset_collection(access="public", project="openwebsearch", dataset_id=d["dataset_id"]))

Produces

2025-07-18 09:00:05,867 -- ERROR -- py4lexis.core.lexis_irods -- log_and_print_errors -- iRODS Exception: error checking session validity
  • After stopping the other two processes, the above script runs normal immediately.
  • My hypothesis is, that the two parallel running jobs do refresh the irods token regularly, but then produce a different session token every time.
  • The problem is, that this limits us to one long standing job per user

Details

I have a long running code (>12h) that regularly access files via irods. Everything is working fine, except that in some point in time (around >10h), irods starts throwing an ExceptionOpenIDAuthUrl: https://aai.lexis.tech/auth/realms/LEXIS_AAI_v2/protocol exception

I traced it down to the following code part in the iRODS() class:

   irods_session: iRODSSession = iRODSSession(host=self.__session.irods_path if self._host is None else self._host,
                                                       port=int(self.__Clr.yhbrr(_irds_prt)) if self._port is None else self._port,
                                                       authentication_scheme=self.__Clr.yhbrr(_sc),
                                                       openid_provider=self.__Clr.yhbrr(_prvdr),
                                                       zone=self._default_zone,
                                                       access_token=self.__session.get_access_token(),
                                                       user=self.__session._tokens.username,
                                                       block_on_authURL=False)

            if not self.__session.suppress_print:
                print(f"The iRODS session was successfully initialised.")

In the debugger, a new irods_session gets created. I have a breakpoint at if not self.__session.supres.... Now when calling irods_session.server_version at this breakpoint, i get the above exception. This indicates, that the session has not been correctly created or there is a mismatch between irods and lexis.

Further test (note that i have overwritten the iRODS() class, so _iRODS__session is the iRODS.session, i.e. the LexisSession) :

  • LexisSession is still valid: Datasets(session=self._iRODS__session).get_all_datasets() returns a list of datasets
  • Creating a new iRODS object yields the same error: iRODS(session=self._iRODS__session)._irds.server_version
  • Creating a new iRODS object with a new Lexis Session using the offline token yields the same error: `iRODS(session=LexisSession(suppress_print=False, in_cli=True,offline_access=True,login_method="offline", refresh_token="my current offline token"))._irds.server_version

I ran the following script (with my offline token):

from py4lexis.core.lexis_irods import iRODS
from py4lexis.core.session import LexisSession
from py4lexis.ddi.datasets import Datasets


lexis_session = LexisSession(suppress_print=False, in_cli=True,offline_access=True,login_method="offline",
                              refresh_token="my offline token is ")
ds = Datasets(session=lexis_session, suppress_print=False).get_all_datasets()
print(ds)
v= iRODS(session=lexis_session)._irds.server_version
print(v)

Output

Connected to pydev debugger (build 251.26094.141)
Welcome to the Py4Lexis!
You have been successfully logged in LEXIS session.
Retrieving data of the datasets...
Data of the datasets successfully retrieved (and converted)....
......some datasets come here from both, lrz and it4i zones.................
Validating token on iRODS...
Validate token on iRODS was successfull...
The iRODS session was successfully initialised.
Traceback (most recent call last):
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/session.py", line 167, in server_version
    return tuple(ast.literal_eval(reported_vsn))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/ast.py", line 64, in literal_eval
    node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/ast.py", line 50, in parse
    return compile(source, filename, mode, flags,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<unknown>", line 0
    
SyntaxError: invalid syntax

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/session.py", line 173, in __server_version
    conn = next(iter(self.pool.active))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/pool.py", line 61, in get_connection
    conn = self.idle.pop()
           ^^^^^^^^^^^^^^^
KeyError: 'pop from an empty set'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mgrani/git/3.ProAndPhD/2209-OWSEU/owi-cli/tests/irods_connection_openidauthurl.py", line 10, in <module>
    v= iRODS(session=lexis_session)._irds.server_version
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/session.py", line 169, in server_version
    return self.__server_version()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/session.py", line 176, in __server_version
    conn = self.pool.get_connection()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/pool.py", line 15, in method_
    ret = method(self,*s,**kw)
          ^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/pool.py", line 77, in get_connection
    conn = Connection(self, self.account, block_on_authURL=self.block_on_authURL)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/connection.py", line 94, in __init__
    self._login_openid()
  File "/home/mgrani/bin/miniforge3/envs/owilix-dev/lib/python3.11/site-packages/irods/connection.py", line 565, in _login_openid
    raise ExceptionOpenIDAuthUrl(first)
irods.connection.ExceptionOpenIDAuthUrl: error checking session validity

I then added a loop to check every dataset with the irods collection:

from py4lexis.core.lexis_irods import iRODS
from py4lexis.core.session import LexisSession
from py4lexis.ddi.datasets import Datasets


lexis_session = LexisSession(suppress_print=False, in_cli=True,offline_access=True,login_method="offline",
                              refresh_token="token ommitted")
ds = Datasets(session=lexis_session, suppress_print=False).get_all_datasets()
print(ds[0:2])
for d in ds:
    print(d["dataset_id"])
    print(iRODS(session=lexis_session).get_dataset_collection(access="public", project="openwebsearch", dataset_id=d["dataset_id"]))
v= iRODS(session=lexis_session)._irds.server_version
print(v)

but it tells me now (in the lexis log)

025-07-18 08:59:04,637 -- ERROR -- py4lexis.core.lexis_irods -- log_and_print_errors -- iRODS Exception: error checking session validity
2025-07-18 08:59:04,638 -- INFO -- py4lexis.core.lexis_irods -- __validate_irds -- iRODS -- VALIDATE TOKEN -- PROGRESS
2025-07-18 08:59:04,638 -- INFO -- py4lexis.core.session -- make_request -- Preparing 'GET' request with no payload.
2025-07-18 08:59:04,842 -- INFO -- py4lexis.core.lexis_irods -- __validate_irds -- iRODS -- VALIDATE TOKEN -- OK
2025-07-18 08:59:04,842 -- INFO -- py4lexis.core.lexis_irods -- __get_irds_session -- iRODS -- INITIALISED -- OK
2025-07-18 08:59:04,842 -- INFO -- py4lexis.core.lexis_irods -- get_dataset_collection -- Getting directory (collection): /IT4ILexisV2/public/proj862c5962623246664c1fda27b7afb108/ed9825ba-6317-11f0-ab83-528c047b29ff
2025-07-18 08:59:04,843 -- INFO -- py4lexis.core.lexis_irods -- __get_collection_with_log -- GET iRODS collection: /IT4ILexisV2/public/proj862c5962623246664c1fda27b7afb108/ed9825ba-6317-11f0-ab83-528c047b29ff

So the session is no longer valid for iRODS, but it is ok for Lexis. The same happens for the URL login method. Does not work.

lexis_session = LexisSession(suppress_print=False, in_cli=True,offline_access=True,login_method="url")

Now i killed the other two processes that have been running under the same account, and the same script works as intended