Question
· Sept 20, 2023

Appel Synchrone d'un Business Process

Bonjour, 

Je souhaite faire un appel synchrone d'un process. En entrée je reçois un flux json qui me déclenche mon business process mais tant que ce flux n'est pas analysé je ne souhaite pas récupérer un autre flux json tant que le premier n'est pas terminé. 

Pour cela j'ai crée un business Service faisant un appel au targetconfigname, or le SendRequestSync ne fonctionne pas, celui ci a le même comportement que le SendRequestAsync : 

Method OnProcessInput(pInput As %RegisteredObject, Output pResponse As exparf.msg.dataXML) As %Status
{
    set tSC                      = $$$OK
    s tHttpRequest               = ##class(%Net.HttpRequest).%New()
    set pContainer               = ##class(Ens.StreamContainer).%New()
    s tHttpRequest.Server        = ..Server

    s tHttpRequest.ContentType   ="application/json"
  
   // set pContainer.Stream        = tHttpRequest.HttpResponse.Data
   // do pContainer.CopyFrom(tHttpRequest.HttpResponse.Data)
    Set jsonObject               = [].%FromJSON(tHttpRequest.HttpResponse.Data)
    Do ##class(%JSON.Formatter).%New().Format(jsonObject)
    set pContainer.Stream         = tHttpRequest.HttpResponse.Data

      for iTarget=1:1:$L(..TargetConfigNames, ",") {
            set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
            $$$TRACE("The target '"_tOneTarget_"' will be called "_$SELECT(..sync=1:"synchronously",..sync=0:"synchronously"))
            
            set tSC1=..SendRequestSync(tOneTarget,pContainer,.pResponse)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        }
    
  return tSC
}

La global s'alimente en permanence avec les mêmes informations. 

J'ai également un soucis de dépendance cyclique 

Je ne sais pas si c'est liée à ce problème. 

Pouvez-vous m'aider s'il vous plait. 

Merci 

Discussion (12)3
Connectez-vous ou inscrivez-vous pour continuer

Bonjour @Julia Pertin, ça va être plus facile à lire vos lignes de code si vous utilisez un codesnippet ici, pas une image. Pour insérer le codesnippet vous cliquez sur le bouton

et insérez votre code dans le popup qui est apparu

Et comme ça, vous aurez ajouté un joli extrait de code formaté, facile à lire et à copier, si nécessaire.

Method OnProcesInput()
{
    write "Hello"
}

Bonjour @Irène Mykhailova ,

 Très bien je vous remercie, voici donc l'extrait de code qui me pose soucis. 

Method OnProcessInput(pInput As %RegisteredObject, Output pResponse As exparf.msg.dataXML) As %Status
{
    set tSC                      = $$$OK
    s tHttpRequest               = ##class(%Net.HttpRequest).%New()
    set pContainer               = ##class(Ens.StreamContainer).%New()
    s tHttpRequest.Server        = ..Server

    s tHttpRequest.ContentType   ="application/json"
  
   // set pContainer.Stream        = tHttpRequest.HttpResponse.Data
   // do pContainer.CopyFrom(tHttpRequest.HttpResponse.Data)
    Set jsonObject               = [].%FromJSON(tHttpRequest.HttpResponse.Data)
    Do ##class(%JSON.Formatter).%New().Format(jsonObject)
    set pContainer.Stream         = tHttpRequest.HttpResponse.Data

      for iTarget=1:1:$L(..TargetConfigNames, ",") {
            set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
            $$$TRACE("The target '"_tOneTarget_"' will be called "_$SELECT(..sync=1:"synchronously",..sync=0:"synchronously"))
            
            set tSC1=..SendRequestSync(tOneTarget,pContainer,.pResponse)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        }
    
  return tSC
}

Bonjour @Lorenzo Scalese

Merci pour votre réponse, en fait je n'ai pas de d'évènement déclencheur. C'est un appel permanent à une API qui me permet de récupérer un flux json et qui va ensuite déclencher le business process. 

Du coup dans la méthode OnProcessInput de Ens.BusinessService,  je fais un appel à l'API, je stock le flux json dans un stream que je passe ensuite au SendRequestSync afin d'éxécuter le business process et j'attends en réponse le dernier message du process avant de refaire un appel à l'API et c'est la que cela ne fonctionne pas car je récupère plusieurs fois ce flux json. 

Bonjour @Julia Pertin,

si j'ai bien compris ton besoin, pour régler ton problème qui consiste à éviter de récupérer plusieurs fois le même flux json, ton Business Service doit servir uniquement à appeler un Business Process, qui lui va se charger de récupérer le flux json pour le passer à une Business Operation.

Dans le cas où ton Business Service appelle le Business Process de manière synchrone, il attendra bien la réponse avant de s'exécuter à nouveau.
Dans le cas contraire, c'est à dire si le Business Process est appelé de manière asynchrone, le Business Service fera un nouvel appel à chaque atteinte du temps prévu par le paramètre "
INTERVALLE ENTRE APPELS".

  

Le code du Business Service :
 

Class EP.service.replication Extends Ens.BusinessService
{

Property Adapter As Ens.InboundAdapter;

Parameter ADAPTER = "Ens.InboundAdapter";

Property TargetConfigNames As %String(MAXLEN = 1000);

Property sync As %Boolean [ InitialExpression = 1 ];

Parameter SETTINGS = "sync:Advanced,TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";

Method OnProcessInput(pInput As %RegisteredObject, Output pResponse As Ens.StringResponse) As %Status
{
  set tSC = $$$OK
  for iTarget=1:1:$L(..TargetConfigNames, ",") {
        set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
        $$$TRACE("The target '"_tOneTarget_"' will be called "_$SELECT(..sync=1:"synchronously",..sync=0:"synchronously"))
        if ..sync {
          set tSC1=..SendRequestSync(tOneTarget,pInput,.pResponse)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        } else {
          set tSC1=..SendRequestAsync(tOneTarget,pInput)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        }
  }
  return tSC
}

/// Return an array of connections for drawing lines on the config diagram
ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
{
	Do ##super(.pArray,pItem)
	If pItem.GetModifiedSetting("TargetConfigNames",.tValue) {
		For i=1:1:$L(tValue,",") { Set tOne=$ZStrip($P(tValue,",",i),"<>W")  Continue:""=tOne  Set pArray(tOne)="" }
	}
}

}

Le code du Business Process

Class EP.process.replication Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ]
{

Property Server As %String [ InitialExpression = "host.docker.internal" ];

Property Port As %Integer [ InitialExpression = 12773 ];

Property classname As %String [ InitialExpression = "data.client" ];

Parameter SETTINGS = "Server:target,Port:target,classname:target";

Method OnRequest(pRequest As Ens.Request, Output pResponse As Ens.StringContainer) As %Status
{
    set sc = $$$OK
    set tHttpRequest             = ##class(%Net.HttpRequest).%New()
    set pContainer               = ##class(Ens.StreamContainer).%New()
    set stream                   = ##class(%Stream.GlobalCharacter).%New()
    set tHttpRequest.Server      = ..Server
    set tHttpRequest.Port        = ..Port
    set location                 = "/common/list/" _ ..classname _ "/json"

    set tHttpRequest.ContentType = "application/json"
    set tHttpRequest.Timeout     = 900
    
    set tSC = tHttpRequest.Get(location)
  
   if $ISOBJECT(tHttpRequest.HttpResponse) {
    Set jsonObject               = [].%FromJSON(tHttpRequest.HttpResponse.Data)
    Do jsonObject.%ToJSON(.stream)
    set pContainer.Stream = stream
    $$$TRACE("stream size:"_stream.Size)
    $$$TRACE("stream data:"_stream.Read(1000))

    set sc = ..SendRequestSync("EP.operation.replication",pContainer,.pResponse)
    
   }
   return sc
}

Storage Default
{
<Data name="replicationDefaultData">
<Subscript>"replication"</Subscript>
<Value name="1">
<Value>Server</Value>
</Value>
<Value name="2">
<Value>Port</Value>
</Value>
<Value name="3">
<Value>classname</Value>
</Value>
</Data>
<DefaultData>replicationDefaultData</DefaultData>
<Type>%Storage.Persistent</Type>
}

}

Le code de la Business Opération

Class EP.operation.replication Extends Ens.BusinessOperation
{

Property Adapter As Ens.OutboundAdapter;

Parameter ADAPTER = "Ens.OutboundAdapter";

Parameter INVOCATION = "Queue";

Method sync(pRequest As Ens.StreamContainer, Output pResponse As Ens.StringContainer) As %Status
{
    set pResponse = ##class(Ens.StringContainer).%New()
    set json = [].%FromJSON(pRequest.Stream)
    set array = json.%GetIterator()
    while array.%GetNext(.key,.value) {
        $$$TRACE("Data:"_value.%ToJSON())
        set a = ##class(data.client2).%New()
        set sc = a.%JSONImport(value)
        if 'sc {
            $$$LOGERROR("ERROR while importing:"_$system.Status.GetErrorText(sc))
        } else {
            set sc = a.%Save()
        }
    }
    set pResponse.StringValue = key _" records inserted"
    return sc
}

XData MessageMap
{
<MapItems>
    <MapItem MessageType="Ens.StreamContainer">
        <Method>sync</Method>
    </MapItem>
</MapItems>
}

}

Bonjour @Julia Pertin 
peux-tu me donner plus de détails sur l'erreur rencontrée ?

Vérifies-bien si tu recrées une production from scratch, en ajoutant service-process-operation, de conserver les noms les BS-BP-BO identiques aux noms des 3 classes EP.service.replication, EP.process.replication et EP.operation.replication, et qu'ils sont bien reliés entre eux.