Dmitry Maslennikov · May 30, 2016 go to post
ToPhone(s = "")
{
 set r=""
 set c=96 
 for p=2:1:9 {
     set k="" 
     for j=1:1:3+(p=7)+(p=9) { 
         set k=k_p
         set c($c($i(c)))=k
     }
 } 
 for i=1:1:$l(s) { 
     set n=$g(c($e(s,i)),0) 
     if $e(n)=$e(r,*) set r=r_" " 
     set r=r_n
 } 
 quit r
}

but WaitMsg it is on parent's side, my control code ususaly like like this

    set resName="someresource"
    job ..someJob(jobsData,resName)
    set child=$zchild
    
    for {
        set $lb(sc,data)=$system.Event.WaitMsg(resName, 1)
        if sc<=0 {
            quit:'$data(^$Job(child))
        }
        continue:data=""
        // do some staff with incomming data
    }

But if you want to interrupt your child process, of course will be possible only from such process, if your process have some loops you may just check if parent still exists, if not, just stop working.

Dmitry Maslennikov · Jun 14, 2016 go to post

Yes, such language extension is very useful, but there is one more feature less known, and unfortunately completely undocumented. Its structured system variables, some of them could me familiar it is: ^$JOB,  ^$LOCK, ^$GLOBAL and ^$ROUTINE. More information in documentation here. But not all knows that it is possible to make your own such global. You should create routine with name SSVN"global_name" in %SYS namespace, for example SSVNZA for ^$ZA global

and for example with this code below, you SET, GET, KILL any values in this global, and this global will contain individual data for every session, and it is possible to use $order or even $query for  such global

ROUTINE SSVNZA
#define global $na(^CacheTemp.ZA($select($isobject($get(%session)):%session.SessionId,1:$job)))

fullName(glob) {
    set global=$$$global
    for i=4:1:glob set global=$na(@global@(glob(i)))
    quit global
}
set(glob, value) public {
    set global=$$fullName(.glob)
    set @global=value
}
get(glob) public {
    set global=$$fullName(.glob)
    quit @global
}
kill(glob, zkill=0) public {
    set global=$$fullName(.glob)
    if zkill {
        zkill @global
    } else {
        kill @global
    }
}
order(glob, dir) public {
    set global=$$fullName(.glob)
    quit $order(@global, dir) 
}
query(glob, dir) public {
    set global=$$fullName(.glob)
    set result=$query(@global, dir)
    quit:result="" ""
    set newGlobal=$name(^$ZA)
    for i=$ql($$$global)+1:1:$ql(result) {
        set newGlobal=$name(@newGlobal@($qs(result,i)))
    }
    quit newGlobal 
}

But as I said before, as it is completely undocumented feature a bit difficult to get complete compatibility with ordinary globals. But it still could be useful, in other cases, like it used by InterSystems.

Dmitry Maslennikov · Jun 17, 2016 go to post

As I've already had some experience in such systems in production, and one of our projects, has similar architecture exclude docker, just on windows, some physical servers with ECP-Client + CSPGateway + Apache, and one HAPorxy server for all of this server. And in this case all this scheme is quite static, and adding new ECP-client means some manual works, on all levels. But with docker I expect, just call something like this command 

docker-compose scale ecp=10

and just get some new working instances, which just after gets their new web-clients

To work it as microservices and split CSPgateway and Cache instance as different containers, I need to have simple package just only with CSPGateway, but FieldTest versions does not contain it. But yes sure, I think it is good way too, and in this case I can have more WEB-containers then Cache does, if it would be needed.

Dmitry Maslennikov · Jul 26, 2016 go to post

Sure, thats needs because this variable should be available in any place for this process, just because this code executes in context where works any output commands like write

In this case, for $match you should define regex which match full given string, so it could looks like

write $Match("Find String ABC",".*(abc|ABC).*")
1

or you can use $locate, which returns position for first matched string

write $locate("Find String ABC","abc|ABC")>0
1

Good article, but unfortunately I don't see the answer for last part for the question "How can I minimize the phenomena?"

So, in my practise, such behavior, in most cases related with some application's buffer globals, or logging globals. And mostly  we don't need in this journal, because it is not important part of our data, and we should not spend important resources for doing this. And we can cut off journalling for such globals. There are some ways to do it: 

  • Remap such globals to another database with disabled journaling. But this way has some exceptions, any changes in transactions, should be journaled in any way.
  • Use ENABLE^%NOJRN to disable journaling non-transact changes, and return back with DISABLE^%NORJN.
  • Remap to database CACHETEMP, which disabled for all changes, even in transaction.

Unfortunately in times when web-applications prevail other types of applications this approach is cannot be widely used. This way can't be used directly in CSP, because of by default any session could be joined to any process, but Procces-private globals is not session-provite globals. And If you need to have such functionality with CSP, you should use Preserve sessions or use something like Sessions-private global, something like this

^CacheTemp.SomeTableD($select($isobject($get(%session)):%session.SessionId,1:$job))
Dmitry Maslennikov · Aug 16, 2016 go to post

What do you mean by dynamic sessions ?
Web sessions in Caché only two types, preserve or not. Preserve just keep working in the same process, for all request in this session, and keeps every locks. By default sessions, instead, only keeps data in %session.Data, and release locks after end of request.

Dmitry Maslennikov · Aug 17, 2016 go to post

if you need add a string, you should concatenate it with operator _

+ converts all types to number, and doing arithmetical operator add

7_"" became "7"
+"5apples" became 5

Dmitry Maslennikov · Aug 17, 2016 go to post

Well, in this case you should set Header Accept, with needed one or more formats, more info in wiki

set %response.SetHeader("Accept","text/plain")
Dmitry Maslennikov · Aug 17, 2016 go to post

So, you had to start with such explanation.

Well, does not matter what do you set in Accept header, if you don't use it by yourself. Like, you should check incoming content type and send an error if it is not accepted. This Header change nothing in incoming data,  if data was sent in another format.

To read data, you should know that %request has three different ways for getting data. You have already known in %request.Content, which usually contains binary streams. Then %request.MimeData, and %request.Data, it is a Multidimensional properties, and %request has some getters for them, %request.GetMimeData and %request.Get. MimeData, needs when client send data in multipart mime format, such as several files or so on. And %request.Data, in all most cases, and you should look at this property and method %request.Get("somename")

Dmitry Maslennikov · Aug 17, 2016 go to post

As I see you a talking about Ensemble REST service. In this case I am not 100% sure, I think pInput only contains some binary data, or json. But forms data any should be available with %request.

Dmitry Maslennikov · Aug 26, 2016 go to post

Yes, you still have to ask user for login password, and should check it in Caché, so, you just should try to connect with user's login/pass, and so, you can validate him.

Dmitry Maslennikov · Aug 27, 2016 go to post

does not matter what `ccontrol list` shows, may be you just removed instance from this list

if you removed this folder, try to restart machine, and check output with commands, which I gave you

What do you mean ?

Atelier can store cache classes in git and in any others source control systems.

even, you can make source control class for studio which will support the same way as in Atelier

If you would work with this  or even look at the documentation by link, which I gave, you would see that DISABLE actually disabled changes which was done by ENABLE^%NOJRN, and name NOJRN says No Journal.

To support Raspberry Pi, IntersSystems should support ARM, but not sure that so easy, and could be valuable for them, even if remember how quickly  they ended GlobalsDB. But GlobalsDB was a quite good product, and was used in some projects, and even still used. If somebody needs to use micro-pc they can use some alternatives on Intel's process such as Intel Galileo

So, you have to modify some entries in AD by data on Caché side.
In first, I have not been done such work before, I'm just trying to suggest what may help you.
Better way to understand what you have to achieve your needs, it's look at classes. Like EnsLib.LDAP.OutboundAdapter which you've already found and %SYS.LDAP which is lowest class, which actually doing all work with LDAP. Actually Enslib.LDAP as I see used deprecated classes from %Net.LDAP.Client.

How it may help? for example? you can find there such method as GetEntryEditObj,  which I think may be used to edit some entries in your AD, if you have enough permissions. Some example you can find in the class for this EntryEdit. Or method ModifyExts in %SYS.LDAP, also has some examples.

Hope it helps.

As I see it's like an emulator x86 on ARM. Ok, then it would be possible, but any way running Caché directly on ARM would be better, and will be a bit easier to find and solve some possible incompatibilities 

Dmitry Maslennikov · Sep 10, 2016 go to post

For now, I need only Data Model and API to get access, in time when even do not have any data model. 
Yes, I know, that we are already have documented api, and will be easier to implement, but I still need some time.

Ok, maybe someone know some testing tool for API, some unit test which can get my base url, and test all functions in that API and says that everything works by standard?