Eduard Lebedyuk · May 27, 2023 go to post

3 times cheaper. Or you can get the compute Savings Plans for AWS Fargate.

Compare prices:

  • On Demand (100%): $0.04048 per vCPU per hour + $0.004445 per GB per hour
  • Spot (31%): $0.01254 per vCPU per hour + $0.00137698 per GB per hour
  • 3 years upfront Compute Savings Plan (48%): $0.0194304 per vCPU per hour + $0.0021336 per GB per hour
Eduard Lebedyuk · May 27, 2023 go to post

At this point I would highly recommend just writing a cfn template, rather than clicking through 30 screens.

Great article though.

Notes:

  1. Split cluster and service/task creations into separate stacks.
  2. By default your cluster would have FARGATE and FARGATE_SPOT capacity providers, but if you use Launch type compute configuration you'll only get Fargate On-Demand. To use Spot you need to use Capacity provider strategy compute configuration and specify Spot.
     
Eduard Lebedyuk · May 25, 2023 go to post

Does your license support IAM? What's the output for this command:

w $SYSTEM.License.GetFeature(21)
Eduard Lebedyuk · May 25, 2023 go to post

As long as you insert only with SQL (without %NOINDEX flag) or objects (%Save), you don't have to rebuild indices. But some gotchas to remember:

  • If the table has some data before you added an index, you need to build the index after adding it (as adding an index does not build it for preexisting data)
  • If you ran sql queries which filtered based on an indexed column value, they won't automatically take advantage of the index, you need to purge all queries associated with the newly indexed table.
  • If you use %NOINDEX or direct global access to add rows, indexes must be built manually later
Eduard Lebedyuk · May 24, 2023 go to post

Here's the code to create task to purge messages in all interoperability namespaces:

set sc = ##class(%SYS.Namespace).ListAll(.result) 
kill result("%SYS"), result("HSCUSTOM"), result("HSLIB"), result("HSSYS"), result("REPO") 
while 1 {set ns = $o(result($g(ns))) quit:ns="" continue:$e(ns,1,2)="^^" set $namespace = ns continue:'##class(%Dictionary.ClassDefinition).%ExistsId("Ens.MessageHeader") set task=##class(%SYS.Task).%New(),task.Name = "Purge old Interoperability data in " _ $namespace,task.NameSpace=$Namespace,task.TimePeriod=0,task.TimePeriodEvery=1,task.DailyFrequency=0,task.DailyFrequencyTime="",task.DailyIncrement="",task.DailyStartTime = 3600,task.DailyEndTime = "",task.StartDate = $p($H,",",1)+1,task.Priority = 2,task.Expires = 0,taskdef = ##class(Ens.Util.Tasks.Purge).%New(),taskdef.BodiesToo = 1,taskdef.KeepIntegrity = 1,taskdef.NumberOfDaysToKeep = 1,taskdef.TypesToPurge = "all",sc = task.AssignSettings(taskdef),task.TaskClass=$classname(taskdef),sc = task.%Save()}
Eduard Lebedyuk · May 23, 2023 go to post

I try to ask all non-sensitive questions on community so that the info would be available publicly.

Eduard Lebedyuk · May 18, 2023 go to post

There was actually supposed to be a hard mode, where rotation can happen in any (of two) directions, but I removed that.

Eduard Lebedyuk · May 18, 2023 go to post

Here's how to fix that.

1. Create Inbound adapter which extends default inbound adapter and exposes DeleteFromServer setting:

Class Test.InboundAdapter Extends EnsLib.File.InboundAdapter
{
Parameter SETTINGS = "DeleteFromServer:Basic";
}

2. Create Passthrough Service, which uses your custom adapter:

Class Test.PassthroughService Extends EnsLib.File.PassthroughService
{
Parameter ADAPTER = "Test.InboundAdapter";
}

3. Use your class (2) when you create a new BS, it will have DeleteFromServer property:

I filed an enhancement request, please use DP-422980 as an identifier if you would contact WRC on this topic.

Eduard Lebedyuk · May 12, 2023 go to post

Recently I wrote a snippet to determine which Business Host took to long to stop:

Class Test.ProdStop
{

/// do ##class(Test.ProdStop).Try()
ClassMethod Try()
{
	set production = ##class(Ens.Director).GetActiveProductionName()
	set rs = ..EnabledFunc(production)
	if rs.%SQLCODE && (rs.%SQLCODE '= 100) {
		write $$$FormatText("Can't get enabled items in %1, SQLCode: %2, Message: %3", production, rs.%SQLCODE, rs.%Message)
		quit
	} 
	
	while rs.%Next() {
		set bh = rs.Name
		set start = $zh
		set sc = ##class(Ens.Director).EnableConfigItem(bh, $$$NO, $$$YES)
		set end = $zh
		set duration = $fn(end-start,"",1)
		write !, $$$FormatText("BH: %1, Stopped in: %2, sc: %3", bh,  duration, $case($$$ISOK(sc), $$$YES:1, :$system.Status.GetErrorText(sc))), !
		if duration>60 {
			write !, $$$FormatText("!!!!!!! BH: %1 TOOK TOO lONG !!!!!!!", bh),!
		}
	}
}

Query Enabled(production) As %SQLQuery
{
SELECT 
	Name 
	, PoolSize
FROM Ens_Config.Item 
WHERE 1=1
	AND Production = :production
	AND Enabled = 1
}

}

It stops BHs one by one, measuring how long it took to stop each one.

I would recommend you try to determine which items are taking too long to stop.

Export production before running this code to avoid manually reenabling all the hosts.

Eduard Lebedyuk · May 10, 2023 go to post
set sda3 = ##class(HS.SDA3.Container).%New()
do sda3.InitializeXMLParse(.stream)
while sda3.GetNextSDA(.type, .obj) {
	// process?
}
Eduard Lebedyuk · Apr 29, 2023 go to post

Check this article.

One of the most simple options - a CSP utility method which outputs all objects as a response. Just add this to any part of your code:

set %response.ContentType = "html"
do ##class(%CSP.Utils).DisplayAllObjects()
return $$$OK
Eduard Lebedyuk · Apr 28, 2023 go to post

Yes, either enable OS authentication for passwordless login or pass user/password as first two lines of the script.

Eduard Lebedyuk · Apr 26, 2023 go to post

Check Ens.Config package - it has all production elements as structured tables/classes.

Eduard Lebedyuk · Apr 24, 2023 go to post

I think it would be easier to write ndjson->json converter. Something like this:

ClassMethod nd2json(file, dir)
{
    set dir = ##class(%File).NormalizeDirectory(dir)
    quit:'##class(%File).Exists(file) $$$ERROR($$$GeneralError, "File " _ file _ " does not exist")
    if '##class(%File).DirectoryExists(dir) {
        do ##class(%File).CreateDirectoryChain(dir)
        
        quit:'##class(%File).DirectoryExists(dir) $$$ERROR($$$GeneralError, "Directory " _ dir _ " does not exist and creation failed")
    }
    
    set stream = ##class(%Stream.FileCharacter).%New()
    do stream.LinkToFile(file)
    while 'stream.AtEnd {
        set json = stream.ReadLine($$$MaxStringLength)
        //set out = ##class(%File).TempFilename("json", dir) // random order
        set out = dir _ $tr($j($i(count), 4), " ", 0) _ ".json" // if the order is important
        set outStream = ##class(%Stream.FileCharacter).%New()
        do outStream.LinkToFile(out)
        do outStream.Write(json)
        do outStream.%Save()
        kill outStream
    }
}
Eduard Lebedyuk · Apr 24, 2023 go to post

Before

set sc=conn.PrepareW(hstmt,sql) 

add:

set sql = $zcvt(sql, "O", "UTF8")

It will make the string UTF8 encoded. Docs.

Eduard Lebedyuk · Apr 24, 2023 go to post

Enabling OS authentication may be an option, but that's a global setting and not (easily) configurable per-user.

But is there a way to configure OS authentication for one user only?

Eduard Lebedyuk · Apr 24, 2023 go to post

Use caution with auto-play: Auto-playing GIFs can be distracting and annoying for some users, so use caution when deciding to have your GIFs auto-play. Consider giving users the option to play or pause the GIF.   

I think that's only videos.

Eduard Lebedyuk · Apr 17, 2023 go to post

ISC's Interoperability business rule editor has some quirks; it does not allow the passing of variables by reference to custom methods

Interesting. Can you post sample code please?

Eduard Lebedyuk · Apr 17, 2023 go to post

Now, why isn't $ZOBJREF() in the documentation?

What's the use case for this function?

Here's some (autotranslated) info about thesefunctions.

Also $zobjref accepts only integers, so you can pass just the part before @:

set a={}
set b={}
set obj1=$zobjref(1)
set obj2=$zobjref("1@Sample.Person")
zw

Results in:

a=<OBJECT REFERENCE>[1@%Library.DynamicObject]
b=<OBJECT REFERENCE>[2@%Library.DynamicObject]
obj1=<OBJECT REFERENCE>[1@%Library.DynamicObject]
obj2=<OBJECT REFERENCE>[1@%Library.DynamicObject]

There's also no guarantee that the object would be the same i.e.:

set a={"a":1}
set b={"b":1}
set aoref = ""_ a
kill a
set c={"c":1}
set obja=$zobjref(aoref)
zw obja
> obja={"c":1}  ; <DYNAMIC OBJECT>
Eduard Lebedyuk · Apr 14, 2023 go to post

Depending on the fidelity you need, something like this would work:

set str = "abc def!  xyz"
set punctuation = "'!""#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~"
set strNoPuncuation = $tr(str, punctuation, $j("", $l(punctuation)))
set strDedupeWhitespaces = $zstrip(strNoPuncuation,"<=>P")
set out = $lfs(strDedupeWhitespaces, " ")

Another approach. Simpler and likely faster but it will merge sentence ends without whitespace afterwards:

set str = "abc def!  xyz"
set strNoPuncuation = $zstrip(str,"*P",," ")
set strDedupeWhitespaces = $zstrip(strNoPuncuation,"<=>P")
set out = $lfs(strDedupeWhitespaces, " ")

Check $translate, $zstrip.

If you want more fidelity/features check %iKnow.Stemming package.