Written by

Solution Architect at Zorgi
Question Lorenzo Scalese · Apr 16, 2022

How to terminate a process without rollback

Hi Community,

When we terminate a process that is in a transaction, the system (fortunately) performs a rollback.

As part of some troubleshooting, I'm wondering if there's a way around this behavior to avoid rollback (or force commit) before termination.

Recently we had an issue on a test server with a process stuck in a huge transaction (around 100GB).

The out-of-control process was suspended and then terminated causing a rollback.

In the case of a test server, this is not really a problem.

If it happens on a production system, depending on the situation we might prefer to avoid rollback (journal volume, server availability, performance...).

We can suspend the process to save time, but then how to terminate it and avoid the rollback.

Although not recommended for obvious reasons, Is it possible?

Thank you.

Product version: HealthShare 2018.1

Comments

Robert Cemper · Apr 17, 2022

It is rather brute force but matches your decision to skip rollbacks: 

while $TLEVEL { TCOMMIT }

to be sure to catch all cases I'd place it in a  %ZSTOP.mac 
It's the reverse of %ZSTART.    >>  docu

0
Lorenzo Scalese  Apr 17, 2022 to Robert Cemper

Hi @Robert Cemper !

Good Idea!

I tested, but unfortunately, It seems already too late, the rollback is already performed.

%ZSTOP routine

ROUTINE %ZSTOP
%ZSTOP
    Quit

SYSTEM
    Set ^zJob($i(^zJob)) = $ZDATETIME($HOROLOG, 3, 1) _" LABEL-SYSTEM (" _ $JOB _ ") "_$NAMESPACE _ " TLEVEL: "_$TLEVEL
    Do ZFORCECOMMIT
    Quit

LOGIN
    Quit
JOB
    Set ^zJob($i(^zJob)) = $ZDATETIME($HOROLOG, 3, 1) _" LABEL-JOB (" _ $JOB _ ") "_$NAMESPACE _ " TLEVEL: "_$TLEVEL
    Do ZFORCECOMMIT
    Quit
CALLLIN
    Quit

ZFORCECOMMIT
    If $Data(^zForceCommit($Job)) {
        While $TLEVEL {
            TCOMMIT
        }
    }
    Quit

Even if the process is in a transaction before "terminate", the ^zJob trace records a $TLEVEL with the value 0.

Maybe it's just not possible (or possible with a not documented procedure).

Thank you.

0
Robert Cemper  Apr 17, 2022 to Lorenzo Scalese

You are right.
But it works in a test within a Try-Catch bloxk
   

     try {
         ;;; run your code
         }
     catch e {  
        if $ze["<RESJOB>" while $TLEVEL { tcommit }
        }
0
Lorenzo Scalese · Apr 18, 2022

Hi @Robert Cemper, @Vitaliy Serdtsev 

Thank you for your replies! I found a solution to do this without any change to an existing code, not simple but It works and could be useful in a critical situation.

I read the code of ^%ETN and see these lines :

UserError() s $zt="UserErrorE"
 i $d(^rOBJ("%ZERROR")) d 
 . n %00000 d ^%ZERROR

So, If we create a "%ZERROR" routine, we have an entry point :

ROUTINE %ZERROR

%ZERROR
    If $Data(^zForceCommit($Job)) { ; to avoid do this for all processes...
        While $TLEVEL {
            TCOMMIT
        }
    }

    Quit

And then, we must terminate the process like that:

Set pid = "1234" ; pid to terminate
Set ^zForceCommit(pid)=""
Zn "%SYS"
Set process = ##class(SYS.Process).%OpenId(pid)
Set sc = process.Terminate(1)

It's important to use the SYS.Process class and the Terminate method with argument 1 to use ^%ETN.

0
Robert Cemper  Apr 18, 2022 to Lorenzo Scalese

GREAT !    yes   without touching the code

0