Hello @Michael Davidovich ,

Did you try to override OnPreDispatch ?

Also you can configure your web application to use a subclass of %CSP.SessionEvents and override OnStartRequest, OnEndRequest .

Set Application = "/csp/YourWebApp"
Do ##class(Security.Applications).Get(Application, .p)
Set p("EventClass") = "YourCSPEventsClassName"
Set sc = ##class(Security.Applications).Modify(Application, .p)

Hello @Benjamin De Boe ,

It's great news that the performance is improved for the tune table.  Given the volume of data on some installations, a tune table could take more than 15 days.  

I hope to see a significant decrease now that we are migrating our installations to IRIS.

However, I have a few comments on the current workings.

SQL Stats are in the code, which makes it very difficult to manage.
If a table has no statistics, when the first query is run, the table tune is executed.  This is great!

However, since it is automatic and the statistics are stored in the class definition, when a developer creates a record in the table and runs a test, it will generate the stats and it will certainly end up in the repository.  We lose the benefit of the automatic execution of the tuning, but even worse we have unrepresentative statistics. 

Another problem: Even if we import the statistics after the deployment of a new version, if we update a class (bug fix), we have to remember to import the corresponding statistics.

All this requires particular vigilance.  I hope that in a future version, there will be a split between the stats and the code.  We can't really commit stats in our application repository because, from one installation to another, the stats can be different depending on how the application is used.

I am thinking of developing a tool to manage SQL statistics:
 - Comparison of production statistics with recalculated statistics on a test server (with a copy of the data).
 - Manual selectivity management for the rare cases where the tune table would not be efficient (to avoid overwriting manually modified values).
 - Identification of statistics that need to be modified in production (due to ratio change, value distribution).

I am working on an application that contains far too many tables to be able to do this work manually.

It's great to have improved the performance of the tune table as well as the documentation (I read it yesterday and it's much clearer) and I hope you will improve the system with the split stats\code.

Thank you!

I agree with @Pietro Montorfano , due to the type of failure it's not possible to know the stop reason.  
Also, If it's an abnormal stop the execution of ZSTOP is not guaranteed.  

Depending on your target, maybe you can execute code on start (ZSTART routine) to clean something when the system has been stopped abnormally.  It could be identified by a trace in your application database or a scan of the messages.log

Hi @Iryna Mykhailova!

Thank you.  This is an interesting example for the community!

I have often used this when I need to expose data in SQL only stored in globals (without related class definition).

I like the possibility of using the stored procedure "as a table": 

ClassMethod ShowData()
{
 	Set rset = ##class(%SQL.Statement).%ExecDirect(,"SELECT * FROM Sample.Human_GetAllOlderThan(?)",65)
 	Do rset.%Display()
}

We can further filter the results with a where clause without changing the code of the custom class query.

Hi @Scott Roth ,

Ten years ago, I implement %ZSTOP routine to execute code when a job process exits or when the instance shutdown.  I removed my code, but the routine looks like this: 

%ZSTOP ; User shutdown routine. 
    Quit
SYSTEM ; Cache stopping
	
	Set oldNs = $Namespace
	
	Try {
		Set $Namespace = "MYAPPNAMESPACE"
		; Do something when stopping the instance.
	}Catch(ex) {}
	
	Set $Namespace = oldNS
    Quit
LOGIN ; a user logs out of Cache (user account or telnet)
    Quit
JOB ; JOB'd process exits. 
	If $Namespace = "MYAPPNAMESPACE" {
		; do something when job process exits
	}
    Quit
CALLIN ; process exits via CALLIN interface. 
    Quit
Logit(entrypoint, caller) PRIVATE ;
    Quit

Hello @Kurt Hofman ,

I experienced a similar problem the last week while testing a library.

To solve it, I created the PYTHONPATH system environment variable with C:\InterSystems\IRISHealth\lib\python\Lib\site-packages\win32;C:\InterSystems\IRISHealth\lib\python\Lib\site-packages\win32\lib.
IRIS need to be restarted to consider any change in an environment variable.

Check If pythoncom39.dll and pywintypes39.dll exist in the directory C:\InterSystems\IRISHealth\lib\python\Lib\site-packages\win32. If they don't exist, copy them. I don't remember the initial directory of these dll files (maybe C:\InterSystems\IRISHealth\mgr\python\pywin32_system32).

I'm a beginner in Python, so maybe a more simple and clean solution exists...

Hope this help.

Hi @Scott Roth ,

The routine ZMIRROR.MAC must be installed in the namespace "%SYS" on each failover member.  It needs the IRISLIB database mounted in RW for installation.

I use ZMIRROR.MAC to execute code when a node becomes primary, in my example I just implement "NotifyBecomePrimary" label :

ZMIRROR
    Quit
    
NotifyBecomePrimary()
    New
    ; https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GHA_mirror#GHA_mirror_set_tunable_params_zmirror_routine
    Try {
        
        Set ns = "MYAPPNAMESPACE"
        If ##class(Config.Namespaces).Exists(ns) {
            JOB ##class(pkg.Class).ClassMethod():(ns):2
        }
        
    } Catch(ex) { } ; just a security
    
    Quit:$Quit 1
    Quit

There are many events available, we can see the list on this documentation page .
What event mirror are you interested in?