This is helpful to see how the scheduler is working. I foudn this because I was having issues with my scheduler. 

However, it does not address this cryptic statemet in the documentation for version 2019:

"There are some limitations to scheduling abilities. For example, if a business host is started by the scheduler but cannot be stopped by the scheduler, this is because the business host is in the middle of a synchronous call. The business host must wait for a response to the call before it can be stopped."

Essentially, the scheduler is useful only for known downtimes. If any job can't be stopped within a timeout period (10 seconds) of the Ens.AlarmResponse -- say it's reading a large file -- then the AlarmResponse is missed, and the ScheduleService doesn't try again.  The job stays alive, and the next file/message is processed, even after the STOP time. It's like an alarm clock with no snooze button, that is shut off by your roommate after 10 seconds.  Who then leaves.

The documentation also says "Use of the schedule setting is not intended or designed as an event signaling device (ok, so it's not a trigger). It is intended to accommodate planned outages and scheduled intervals of activity or inactivity." But if you're not alreay inactive, then it won't successfully schedule the inactivity.  If you're not in the room when the alarm sounds, it won't successfully schedule the activity.

I'd like to see it keep trying until it hears back from all hosts that use a schedule, or have some parameters that can be set to check every n seconds for a response, try m times, until a certain time; perhaps per business host.

For future readers; I ran into this problem as well, and even setting up my rule carefully exactly as indicated, and with the constraint: msgClass=Ens.StreamContainer, it did not work.  I continued to get Error#5005 Cannot open file.

I found that it was the Operation that was not able to open the file in the Service's File Path.  

I ensured the file service sent the file synchronously to the routing rule by keeping the Archive and Work paths blank.

The final step necessary was to set the Force Sync Send on the RouteRXPFile RULE, to force the rule to send synchronously as well.  That allowed the Operation time to read the file before it was deleted, and send the file on to some other service on a different server / path.

Ah, I should mention that this is happening in code that I can't access.  I can't really tel what's going on except by looking in the database after it's all "said and done". I can try that with one particular row in the database, but it's happening upstream, in othercode, and I'm wondering now if it's because the other code is possibly saving the Claim object differentlly.

However, this is a good idea.  I'll play arond with a couple of objects that are already in the database, and se if I can save them to be "right side up", and then "upside down" again.

I found the other method that needs to be overidden.  It's the XMLImportSDAString method.  This method was already making allowances for the "%" character for the HS.SDA3.CodeTableDetail.UoM class, so I follows the example and added my valid characters when it's importing SDA for the HS.Local.SDA3.CodeTableDetail.xProcedureModifier class.

Hi Harshdeep,

It's not something I read so much as figured out the hard way.  But here is the link to the HS.SDA3.CodeTableDetail.CareProvider object:

https://docs.intersystems.com/irisforhealthlatest/csp/documatic/%25CSP.D...

Which says, "In the Viewer Cache, CareProviders are matched on Code, SDACodingStandard,
Description, and CareProviderType (which is itself a code table). Other
properties are updated if different."

I think that the "matched on" properties are required in order to store the object.  So, setting a Name, but not a Code, will not store the object (this was my example).

As for the properties in FHIR that will map to the necessary SDA properties... you'll have to find the Schema Documentation for FHIR, on your instance's System Management Portal. I think that will be under HealthShare / HealthShareManagement  / Schema Documentation / FHIR Annotations. 

Possibly that will help.

James,

Using Ensemble 2018.1.2, I'm using the pInput.Attributes("FTPDir") to get the full difectory of the filename (where pInput is %Stream.Object) when I have a root directory defined (e.g. /send) and the property Subdirectory Levels = 2.

I also, was trying to find a way  to use the subfolders of the file that's on the server to either run a rule or more simply, create the same folders on our side.  When the production service uses Subdirectory Levels, this subfolder information is not part of the ..Adapter.FilePath (e.g. the root folder is /send, the file is /send/sub1/sub2/testfile.txt, Subdirectory Levels=2, but the Adapter.FilePath = /send/testfile.txt)

However, using the FTPDir attribute of the %Stream.Object gives me the full directory of the source object, from which I can "piece" together appropriate storage path on our end.

Thanks!

Hi Keith, I am sorry! In a SQL database (MySQL, Oracle...), is there a way to drop a table (not a view; a Table) without deleting data?

If you really want to remove the SQL table but keep the data, you can merge the global that stores the actual data into a diffefrent global, such as merge ^SavedData = ^Package.TablenameD (You have to find the right global name from the Storage in the class).

This could take a few minutes to complete. Then you can delete the class.  I don't recommend this.

I suggest you contact IS to help you create a table definition that can be indexed, and perhaps populate this new table with your current data - perhaps a new table will be more efficient. IS is very helpful when it comes to support. And, let us know how it goes!

Thanks,

Laura

Arnold, it could be a scope problem / zen expression problem.

Try something like this:

Property currentTableRow As %ZEN.Datatype.string(MAXLEN = 5000);
 

Method MyMethodOnServer() [ZenMethod] {

set %page.currentTableRow="1"
&js<alert("zenPage.ExportQuery="+#(%page.currentTableRow)#);>

}

I had trouble with a longer string. For a string that's not a number, try this:

set %page.currentTableRow="line 1"

set str=..QuoteJS(%page.currentTableRow)
&js<alert("zenPage.ExportQuery="+#(str)#);>

 

Hey Keith, how's it going from this time last year?  Caché was my first language (actually, it was MUMPS then), and I've always worked with data stored in globals.  When I learned SQL, MySQL, and Java, I realized that I could probably never go to a language where I coudln't "see" the actual data.   Having to rely on tables and SQL and not be able to get to the actual data stored on disk? I'd feel  like I did when I was using chopsticks for the first time.  

When I tell other non-InterSystems programmers how we have access to the actual data, they're flabbergasted and amazed. But, that is the key to understanding the Storage in each class (which by now, you're probably quite familiar with).   SQL will read this Storage "map" which maps the properties to the global storage, and picks it out of the global for us.  

Back in the old days, we would create our own global structure to hold the data.  Globals often looked like ^Point(pointId,"X")=3  and ^Point(pointId,"Y")=4, or more often, ^Reg(PatientId,"Name")="Smith,Amy", or ^Patient(PatientId,1)=Name^age^DOB^ZipCode and ^PatientIndex("Smith,Amy",PatientId)="" and ^Patient("Count")=last PatientId

Any IDX programmers here?  We had a entire book just to understand the globals.

These days, we let InterSystems create the global structure for us, which appears in the Storage definition when a class is compiled, but it's still the same as before -- the data is still stored in a global, and you can edit it and delete it from the global - not recommended though because IS keeps track of counters.

Anyway, I'm sure you're all set, but I thought it might help someone reading this to know the history of data storage and how it's a completely different paradigm than other databases. 

Also, I was looking for the best way to delete the storage from a deleted property.  You know - you delete the property, but don't delete the storage element, and the node is still there in the global?  Normally, this wouldn't ever be noticed, because when using SQL, you don't see the deleted property, but in our case, we are using the global's stucture to view certain structures in the data (it's a bunch of arrays of Objects).  The deleted property's storage was getting in our way.

I decided the best way to delete the leftover data was to simply kill the nodes: ^Test.Package.ClassNameD(id,"TestProperty")=""

This would have been impossible with SQL because the property doesn't exist anymore!

Thanks,

Laura

Hi Arnold,

Regarding you error, looks like Cristiano is correct when he said that %DrawHTML writes only to a device, which is what I am doing (%File) so that works for me.  Drawing it to a string won't work. A very roundabout way would be to write the HTML to a file, and then read the file into the body of an email ... 

As for getRowData(), you'd want to start in a ClientMethod (js) and loop through the table's rows, getting the data for each row, and sending that to the server, perhaps to be stored in a global until you're done? Perhaps passing a large JSON would be better, but I don't have that experience. When you're done on the client, you'd go back to the server, loop through your global, and build your email body.  However, I know from experience that getRowData() is very slow, and should be used to get only the 1 row that you need -- it's not good for looping through to get the all of the data.

In that case, perhaps you should revisit Crisitano's suggestion of just running the table's query again, and using the resulting ResultSet to get and print out the data in a pretty HTML string.  I haven't used %DisplayFormatted, but that might have lots of options for you.

Hi Vivek,

We bought a license for CoolUtils (coolutils.com), whch also has  command line  functionality.  There are dozens of different converters with CoolUtils, but you can buy just the one.

We use a batch file for the command line, which will take two parameters, and an "option file" (used by the converter):

"C:\Program Files (x86)\TotalHTMLConverter\HTMLConverter.exe" "%1" "%2" -c pdf -fp -combine -si -pc Normal -ps letter -OptionFile %3

then call the batch file using $zf:

set command=dir_"Converters\html\ConvertHtmlToPDF.BAT"
set params(1)=fromHTMLfilename

set params(2)=toPDFfilename

set params(3)=OptionFileName

; NEXT: $ZF(-1) NOT USED BECAUSE ANY PROBLEM WITH THE CONVERTER PROGRAM WOULD CAUSE THIS PROCESS TO HANG UNTIL ETERNITY!!!
; Fire off HTML>PDF Converter program in background (-2 = don't wait)
status=$ZF(-100,"/ASYNC",command,.params)

 

The OptionFile has PDF codes like:

po=Landscape
PgHead=&b&d &t
PgFoot=&bPage &p of &P&bInsights powered by RevenueHealth Systems (C) 2018

I used the utility's "Command Line Parameters" help file to figure out how to set all the options, and how to use the option file.  I wrote a note to myself to "See http://www.verydoc.com/htmlprint-footer-header.html" for use on the pdf codes that are in the option file. 

It took a while, and I had to program in a new "language" of PDF options and stuff.

Good luck!

Hi Arnold,

I do exactly that with the built in tablePane method %DrawHTML()

My method uses code like this:

//get tablePane component - copy to new object? (pointers, etc.)
#dim tblPane as %ZEN.Component.tablePane
set tblPane=%page.%GetComponentById("tblPaneData")
// you have access to the columns here, if you need to change things up
set numCols = tblPane.columns.Size
set lastCol = tblPane.columns.GetAt(numCols)
set hidden = lastCol.hidden
set lastCol.hidden=1

// I'm writing this to a file, for use in a moment...
$$$ThrowOnError(File.Open("WNS",10)) Use File.Name

//Draw HTML headers - Note: HTML is not my strong point
"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 transitional//EN"">",!
"<html>",!

//custom style just for this table (see elements in browser debugger! )

//I must have looked at the tablePane in the browser debugger
"<style>",!
  W "h1,h2 {",!
  W "font-size: 20px;",!
  W "font-weight:bold;",!
  W "font-family: verdana;",!
  W "text-align: left;",!
"}",!
// etc. etc.
"</style>",!

"<head>",!
 W "<meta http-equiv=""Content-Type"" content=""text/css"" charset=""UTF-8"">",!
"</head>",!
"<body>",!

//Write specific table header
set header=$g(%session.Data("Heading One Here"))
"<h1>"_header_"</h1>",!
"<h2>Heading Two Here</h2>",!

//write tablepane element to file
do tblPane.%DrawHTML()

//Finish HTML
" </body>",!
"</html>"

//Close File
do File.Close()

 

Perhaps you can return  string of HTML for your email. We use the html  converted to PDF using a third party converter  tool.  This lets the user print the table.

I hope this helps!

Just a note: I haven't had time to log the $s values yet, but I'm thinking that's the way to go to track down the "leak".  I did add the %UnSwizzle, but it didn't help enough. When I point the clone's Youngest property to a new Child, the previous youngest Child still exists in memory, and I feel like that is a problem.

I'll update this thread when I get a chance to test.

Thanks for the help,

Laura