Eduard Lebedyuk · Jul 2, 2022 go to post

What about defining a super parent, which is the only node with a NULL parent?

In that case every other root node has this node as a parent and filtering is easy (WHERE parent IS NULL filters only the super parent). And there's no need for an additional calculated property in that case.

Eduard Lebedyuk · Jun 29, 2022 go to post

If it's a non-production instance you can try running iris windows service (IRIS controller for IRISHEALTH in your case) under your windows user account, instead of the default system one. That usually helps.

If it's not possible, either give system account rights to irissession  or create a new user with rights for irissession and run the iris service under that account.

Eduard Lebedyuk · Jun 17, 2022 go to post

Use Merge in your Business Service:

Set genericRequest = ##class(Core.API.V1.Msg.GenericRequest).%New()
Merge genericRequest.urlParameters = %request.Data

And in BusinessOperation you can use this syntax:

genericRequest.urlParameters("key")
Eduard Lebedyuk · Jun 13, 2022 go to post

DTLs work in-proc rather than in-queue so you can avoid the creation of new messages altogether.

To be specific let's say you have a DTL:

<transform sourceClass='Ens.StringRequest' targetClass='Ens.StringResponse' create='new' language='objectscript' >
<assign value='source.StringValue' property='target.StringValue' action='set' />
</transform>

It would be compiled into this (simplified for clarity):

Transform(source,target,aux="") {
	Set (tSC,tSCTrans,tSCGet)=1
	Set target = ##class(Ens.StringResponse).%New()
	Do:$S($D(%Ensemble("DoTrace")):%Ensemble("DoTrace"),1:##class(Ens.Util.Trace).DoTrace()) ##class(Ens.Util.Trace).WriteTrace("xform",$classname(),"Transform","transform from source "_source_$S(source.%Extends("%Persistent"):"/"_source.%Id(),1:"")_" to target "_target_$S(target.%Extends("%Persistent"):"/"_target.%Id(),1:"")_"")
	Try { Set zVALz=source.StringValue, zVALz=$S($IsObject(zVALz):zVALz.%ConstructClone(), 1:zVALz) }
	Catch ex { If (..#IGNOREMISSINGSOURCE&&($$GetOneStatusText^%apiOBJ(ex.AsStatus())["<INVALID OREF>")) { Set tIgnore=1 } Else { Set tSC=ex.AsStatus() } }
	If 'tIgnore { Set target.StringValue=zVALz }
}

As you see the only new message is response and request/aux are not saved anywhere.

The same holds true for BPL invocations. Assuming this process:

<process language='objectscript' request='Ens.StringRequest' response='Ens.StringResponse' height='2000' width='2000' >
<sequence xend='200' yend='350' >
<transform name='dtl' class='dtl.dtl' source='request' target='response' xpos='200' ypos='250' />
</sequence>
</process>

You'll have this S method:

Method S1(process As Ens.BusinessProcess, context As Ens.BP.Context, synctimedout As %Boolean, syncresponses As %ArrayOfObjects(ELEMENTTYPE="%Library.Persistent"), request As %Library.Persistent, response As %Library.Persistent) As %Status [ Language = objectscript, PublicList = (process, context) ]
{
 Set $ZT="Trap",status=$$$OK do {
 Set iscTemp=$G(response)
 Set status=$classmethod("dtl.dtl","Transform",request,.iscTemp,"")
 If $$$ISERR(status) Quit
 Set response=iscTemp
 Do process.ClearAllPendingResponses()
 Set ..%NextState="Stop"
 } while (0)
Exit Quit ..ManageState(status)
Trap Set $ZT="",status=..ManageStatus(status,"S1") Goto Exit
}

which does nothing except for calling a Transform method. No queueing is used throughout DTL usage.

So, there are several options.

1. Do not create a new message, but rather pass your existing message. DTLs do not modify source or aux messages.

2. Use a registered, rather than a persistent class to pass values - in that case it won't be saved at all.

Eduard Lebedyuk · Jun 9, 2022 go to post

When I developed this query I was concerned with large globals, certainly if there's an interest in small globals' size this might come useful.

Eduard Lebedyuk · Jun 6, 2022 go to post
object="991@%Library.DynamicObject"

Somewhere the object was written into a global and read from it.

Eduard Lebedyuk · May 29, 2022 go to post

You can also call it like this:
 

set rs = ##class(GMECC.DocmanConnect.Tables.vwNewGPs).GetRowsFunc()
while rs.%Next() { do rs.%Print() }

More info about implicit methods.

Eduard Lebedyuk · May 26, 2022 go to post

Modifying initial request is debatable .
Rather I'd recommend setting a status variable to callrequest.Stream.CopyFrom(request.Stream).
This way request remains immutable.

Eduard Lebedyuk · May 25, 2022 go to post

Windows error codes are here.

ERROR_SHARING_VIOLATION

32 (0x20)

The process cannot access the file because it is being used by another process.

Eduard Lebedyuk · May 11, 2022 go to post

I think we can safely consider this contest closed. Honestly, it's more of a discussion than a contest.

Eduard Lebedyuk · May 8, 2022 go to post

Please post SQL plans for slow queries and class def.

WRC handles SQL performance issues.

Eduard Lebedyuk · May 6, 2022 go to post

Try:

Set production = ##class(Ens.Config.Production).%OpenId(productionId)
Set item = ##class(Ens.Config.Item).%OpenId(itemId)
Do production.RemoveItem(item)
Set sc = production.%Save()
Eduard Lebedyuk · May 6, 2022 go to post

Nice use of routines. I think it's a first time we're seen routines in classmethods for code golf.

Eduard Lebedyuk · Apr 9, 2022 go to post

Using cap-add might allow for a more fine-grained control:

--cap-add SETUID --cap-add DAC_OVERRIDE --cap-add FOWNER --cap-add SETGID --cap-add KILL

Or in docker compose:

version: '2'
services:
  iris:
    cap_add:
    - SETUID
    - DAC_OVERRIDE
    - FOWNER
    - SETGID 
    - KILL
Eduard Lebedyuk · Apr 7, 2022 go to post

Is it OK to use this partially rebuilt index  

Sure, as long as you're OK with getting partially consistent results.

Eduard Lebedyuk · Mar 30, 2022 go to post

I've seen solutions with files, and one way to do it would be to write the routines to files, and compare those, but I'd like to avoid that if possible.

I would highly recommend you use a file approach, i.e. git. Write routines to files and compare them using git diff tools.

Eduard Lebedyuk · Mar 29, 2022 go to post

That is a very good question related to an extremely broad topic I usually term as "Advanced Production Management". Should write a book on that. Maybe some day.

Anyway, production management tools are good, but they are generic - they work for any production. The problems start to arise when you need to perform some application specific management. In that case I recommend writing an SQL query.

While interoperability contains a lot of utility tables, you can start with Ens.MessageHeader and its' properties. It's a table containing message headers for all messages - specifically where they come from and where they go to. Join this table to your actual message using MessageBodyClassName and MessageBodyId values.

After that you'll need to filter by all the common criteria - business host, timestamp (id!), some structured message body or header properties. The goal here is to minimize the dataset we'll perform a full text search on.

Finally, after you got your dataset, expose FindAt as an SQL procedure and add it to the query conditions.