RAC Rolling is a very important feature for customers who want to patch their Oracle Database with no downtime. Now, with the new AutoUpgrade 26.2, customers can use RAC Rolling mode with AutoUpgrade, having full control over the shutdown/startup of the instances! In this article, I will show how to do this.
Let’s get started!
How does it work?
The basic concept of the RAC Rolling patch applies is that you never shut down all the instances of your database at the same time.
So, imagine you have a 2-node RAC running in your system. You would:
- Announce that instance 1 is stopping and wait for connections to reconnect on instance 2.
- Now, stop instance 1, move it to a new patched Oracle Home, and start it again.
- Announce that instance 2 is stopping and wait for connections to reconnect on instance 1.
- Now, stop instance 2, move it to a new patched Oracle Home, and start it again.
- After all node binaries are patched, the final part is to patch the dictionary layer of the database.
To implement that with AutoUpgrade, we had to add two new parameters:
- One to control if RAC Rolling feature should be enabled or not.
- Another one to control how long we should wait to stop the instances (drain timeout). Here, you can even control that AutoUpgrade should only stop an instance after your “GO”.
Let’s talk about them.
Config parameter rac_rolling
This parameter will define if the patching should occur or not using the RAC Rolling method.
The accepted values for it are:
- DISABLED
RAC Rolling will not be used. This will force the previous (current) behaviour. All RAC nodes will be stopped and patched, so database downtime will happen during the patching window. Please note that we will have this parameter as “default” for the first release (26.2) when this feature is available, and change the default to AUTO starting on 26.3 (probably), so we keep the same behaviour as before while the feature is on its first release.
- REQUIRED
RAC Rolling must be used. This will only move forward with the patching operation if RAC Rolling is possible. So if any conditions may not allow RAC Rolling, we will stop before touching anything. Example of conditions that would stop AU:
-
- The database is not running on a RAC.
- There is a patch deployed on the target Oracle Home that is not RAC Rolling.
- FORCE
Use with caution. This is the same as REQUIRED, but we will ignore the check results that would not allow RAC Rolling to proceed. So basically, we force the use of the RAC Rolling method.
This value would be useful, for example, if you applied a Data Pump Bundle Patch (which is non-RAC Rolling), but you don’t have any Data Pump jobs running in your environment.
- AUTO (default)
The default value of AUTO will automatically decide the best approach, deciding between DISABLED or REQUIRED. If all the preconditions below are met, then AUTO is resolved as REQUIRED. Otherwise, AUTO is resolved as DISABLED:
-
- The database is in RAC mode.
- All the patches applied to the new home are RAC Rolling.
Config parameter drain_timeout
This parameter will define how long AutoUpgrade should wait, in seconds, until the sessions are drained.
The accepted values for it are:
- (INTEGER VALUE >= 0)
If you provide any integer value higher than 0, this will be passed to the command below that will stop each instance individually:
srvctl stop instance \ -instance %node% \ -stopoption IMMEDIATE \ -drain_timeout %number% \ -failover \ -verbose \ -force
In other words, we will stop the services immediately, move them to any other node (-failover), and ask the sessions to reconnect and continue their workload on another instance. The sessions that don’t have an open transaction will not be allowed to continue. The other sessions that have uncommitted work in progress will have the %number% seconds before they are killed. If all sessions draining completes before the drain timeout value is reached, then AU moves to the next step immediately.
Sessions that have AC/TAC configured are able to continue their uncommitted work in the surviving instance (more on that in the example below).
If 0(ZERO) value is provided, then sessions are immediately killed after the service is relocated.
- NULL
If you don’t provide anything to this parameter, AU will execute:
srvctl stop instance \ -instance %node% \ -stopoption IMMEDIATE \ -failover \ -verbose \ -force
This is the same command as before, but without specifying the -drain_timeout. In this case, what the RAC will do is use the maximum drain timeout of all currently up and running services on the instance that we are stopping.
Example: say the instance on node1 has 2 services running:
– sales_srv (created with a default value of drain_timeout of 30 seconds)
– marketing_srv (created with a default value of drain_timeout of 60 seconds)\
In this case, the stop instance will work by waiting 60 seconds (the maximum between the 2) before the sessions are killed and the instance is stopped.
- WAIT
When the keyword WAIT is provided, the RAC Rolling process will behave in a different way. In this method, we give the end-user full control of when AU will go ahead and stop each of the instances.
First, we will relocate the services running on the instance on any other node. That way, any new session will already connect into another node. After that, we will wait until the user type the proceed command on the AutoUpgrade command line interface. When this command is given, we will continue with the stop command of the instance.
In other words, what we will do is, first call:
srvctl relocate service \ -oldinst %node% \ -stopoption TRANSACTIONAL \ -drain_timeout 2592000 \ -wait yes \ -verbose
Note that the stopoption here is TRANSACTIONAL, meaning that we will first relocate the service to a surviving node and, next, wait for sessions to finish their transactions, waiting indefinitely (well, actually it is 30 days). As soon as a session commits a transaction, it will not be allowed to continue here and will have to connect to another node.
Now, the AU console will be waiting for you to type proceed -job %job_number%. It is going to wait even when there are no more connections using the instance; you have the control. When proceed is finally provided, AU will continue with:
srvctl stop instance \ -instance %node% \ -stopoption IMMEDIATE \ -drain_timeout 0 \ -failover \ -verbose \ -force
This means we will immediately stop the instance and kill any ongoing transactions.
Trying the feature
Let’s finally play with this new feature:
First, download the latest release of AutoUpgrade and ensure it is at least 26.2:
$ wget https://download.oracle.com/otn-pub/otn_software/autoupgrade.jar --2026-02-04 13:46:04-- https://download.oracle.com/otn-pub/otn_software/autoupgrade.jar Resolving download.oracle.com (download.oracle.com)... 23.37.8.103 Connecting to download.oracle.com (download.oracle.com)|23.37.8.103|:443... connected. HTTP request sent, awaiting response... 302 Moved Temporarily Location: https://edelivery.oracle.com/otn-pub/otn_software/autoupgrade.jar [following] --2026-02-04 13:46:05-- https://edelivery.oracle.com/otn-pub/otn_software/autoupgrade.jar Resolving edelivery.oracle.com (edelivery.oracle.com)... 23.55.213.198, 2600:1419:6200:10a8::366, 2600:1419:6200:10bb::366 Connecting to edelivery.oracle.com (edelivery.oracle.com)|23.55.213.198|:443... connected. HTTP request sent, awaiting response... 302 Moved Temporarily Location: https://download.oracle.com/otn-pub/otn_software/autoupgrade.jar?AuthParam=1770212885_5d957e026f73e3b40d9fc1a392869a7b [following] --2026-02-04 13:46:05-- https://download.oracle.com/otn-pub/otn_software/autoupgrade.jar?AuthParam=1770212885_5d957e026f73e3b40d9fc1a392869a7b Connecting to download.oracle.com (download.oracle.com)|23.37.8.103|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 6729677 (6.4M) [application/x-jar] Saving to: ‘autoupgrade.jar’ 100%[=====================================================================================================================================================>] 6,729,677 --.-K/s in 0.1s 2026-02-04 13:46:06 (52.8 MB/s) - ‘autoupgrade.jar’ saved [6729677/6729677]
Now, let’s create a config file with the following entries:
$ cat > patch.cfg << 'EOF' global.global_log_dir=/home/oracle/autoupgrade/log global.keystore=/home/oracle/autoupgrade/keystore patch1.sid=DB19C1 patch1.source_home=/u01/app/oracle/product/19.27.0.0/dbhome_1 patch1.target_home=/u01/app/oracle/product/%RELEASE%.%UPDATE%.0.0/dbhome_1 patch1.restoration=YES patch1.folder=/home/oracle/autoupgrade/patches patch1.patch=RU,OJVM,OPATCH,OCW patch1.download=NO patch1.rac_rolling=REQUIRED patch1.home_settings.ignore_prereq_failure=YES EOF
I’m using rac_rolling as REQUIRED, meaning my patch process must go RAC Rolling.
As I’m short of swap space, I had to use ignore_prereq_failure so my install won’t fail.
Now let’s test if I can have a running SQL that will not stop, using Transparent Application Continuity, while the RAC is being patched. I will prepare my environment.
First, adding my TAC service and starting it up:
$ srvctl add service \ -db DB19C \ -pdb PDB1 \ -service PDB1_TAC \ -preferred DB19C1,DB19C2 \ -policy AUTOMATIC \ -failovertype AUTO \ -commit_outcome TRUE \ -replay_init_time 36000 \ -failoverretry 30 \ -failoverdelay 5 $ srvctl start service -service PDB1_TAC -db DB19C
Next, I will connect to my PDB1 as SYS and create a user and some objects:
SQL> conn system/welcome1@pdb1_tac
Connected.
SQL> create user rodrigo identified by "welcome1";
User RODRIGO created.
SQL> grant dba to rodrigo;
Grant succeeded.
SQL> conn rodrigo/welcome1@PDB1_TAC
Connected.
SQL> create table ac_test (
2 inst_id number,
3 ins_ts timestamp
4* );
Table AC_TEST created.
SQL> create or replace procedure ac_log is
2 pragma autonomous_transaction;
3 begin
4 insert into ac_test (inst_id, ins_ts)
5 values (sys_context('USERENV','INSTANCE'), systimestamp);
6 commit;
7 end;
8* /
Procedure AC_LOG compiled
Next, let’s check if our connection is really using TAC before we start the tests:
SQL> select name, 2 failover_type, 3 failover_retries, 4 failover_delay, 5 failover_restore 6* from dba_services; NAME FAILOVER_TYPE FAILOVER_RETRIES FAILOVER_DELAY FAILOVER_RESTORE ___________ ________________ ___________________ _________________ ___________________ PDB1 PDB1_TAC AUTO 30 5 AUTO SQL> select module, 2 service_name, 3 to_char(logon_time, 'dd-mon-yyyy hh24:mi:ss') as logon_time, 4 failover_type, 5 failover_method, 6 failed_over 7 from v$session 8 where username = USER 9* order by osuser; MODULE SERVICE_NAME LOGON_TIME FAILOVER_TYPE FAILOVER_METHOD FAILED_OVER _________ _______________ _______________________ ________________ __________________ ______________ SQLcl PDB1_TAC 10-feb-2026 12:32:00 AUTO NONE NO
From the queries above, we can see that:
- PDB1_TAC has failover_type set to AUTO, indicating that TAC is enabled for this service.
- The current connection of my user is to PDB1_TAC and has failover_type set to AUTO. So TAC is all set!
Finally, let me put some load:
SQL> insert into ac_test (inst_id, ins_ts) 2* values (0, systimestamp+1); 1 row inserted. SQL> begin 2 loop 3 ac_log; 4 dbms_lock.sleep(30); 5 end loop; 6 end; 7* /
While the script above is running in terminal 1, I can now run it in another terminal 2:
$ $ORACLE_HOME/jdk/bin/java -jar autoupgrade.jar -patch -config patch.cfg -mode deploy ... ---- Drop GRP at your convenience once you consider it is no longer needed ---- Drop GRP from DB19C1: drop restore point AU_PATCHING_9212_DB19C1927000 Please check the summary report at: /home/oracle/autoupgrade/log/cfgtoollogs/patch/auto/status/status.html /home/oracle/autoupgrade/log/cfgtoollogs/patch/auto/status/status.log $
After the code completes, if I check the ac_test table contents, I can see:
... Instance=1 Time=2026-02-10 13:24:36 Instance=1 Time=2026-02-10 13:25:06 Instance=1 Time=2026-02-10 13:25:36 Instance=1 Time=2026-02-10 13:26:06 Instance=1 Time=2026-02-10 13:26:36 Instance=1 Time=2026-02-10 13:27:06 Instance=2 Time=2026-02-10 13:27:31 Instance=2 Time=2026-02-10 13:28:01 Instance=2 Time=2026-02-10 13:28:31 Instance=2 Time=2026-02-10 13:29:01 Instance=2 Time=2026-02-10 13:29:31 Instance=2 Time=2026-02-10 13:30:01 Instance=2 Time=2026-02-10 13:30:31 Instance=2 Time=2026-02-10 13:31:01 Instance=1 Time=2026-02-10 13:31:15 Instance=1 Time=2026-02-10 13:31:45 Instance=1 Time=2026-02-10 13:32:15 Instance=1 Time=2026-02-10 13:32:45 Instance=1 Time=2026-02-10 13:33:15 ..
As we can check, at 13:27:31 the PL/SQL transitioned instance 2 to 1, because instance 1 was moved to the new Oracle Home, and at 13:31:15 it switched back from instance 2 to 1 for the same reasons.
Note that the PL/SQL remains executing, without having to be manually restarted. Also, what is curious, is that the first insert values (0, systimestamp+1) remained uncommitted. If I run alter system cancel sql to stop the loop and later commit, I will get:
... Instance=1 Time=2026-02-10 14:07:48 Instance=0 Time=2026-02-11 12:34:31
So this shows that the uncommitted data that started even before node 1 was patched was preserved when the session moved between the instances!
Happy zero-downtime patching!
Have you enjoyed? Please leave a comment or give a 👍!





2 comments
Hi,
Does this feature work on RAC one Node?
Does it run srvctl relocate database -db xx -node ..?
Author
No, currently RAC One Node are not patching in a Rolling method but the database relocation is in our plans.