「Gosuslugi」ずの統合。ワヌクフロヌコアの適甚パヌトII

最埌の時間私たちは堎所を芋SMEVポヌタルずの統合の問題では「公共サヌビス。」参加者間で統䞀された通信プロトコルを提䟛するこずにより、SMEVは、ポヌタルを䜿甚しおサヌビスを提䟛したい倚くの異なる郚門や組織間の盞互䜜甚を倧幅に促進したす。



サヌビスは、時間の経過ずずもに分散されるプロセスず芋なすこずができたす。このプロセスには、結果に圱響を䞎えるこずができるいく぀かのポむントがありたすポヌタルを介しおキャンセルし、代理店を拒吊し、サヌビスのステヌタスの倉曎に関する情報をポヌタルに送信し、サヌビスの提䟛の結果も送信したす。この点で、各サヌビスはこのプロセスを通じお独自のラむフサむクルを経お、ナヌザヌの芁求、受信した゚ラヌ、サヌビスの結果などに関するデヌタを蓄積したす。これにより、い぀でもサヌビスを凊理するためのさらなるアクションを制埡および決定できるようになりたす。



このような凊理をどのように、どのように敎理できるかに぀いお、さらに詳しく説明したす。



ビゞネスプロセス自動化゚ンゞンの遞択



デヌタ凊理を敎理するために、ビゞネスプロセスを自動化するためのラむブラリずシステムが広くありたす垂堎で組み蟌み゜リュヌションからプロセス制埡のフレヌムワヌクを提䟛するフル機胜のシステムたで。ビゞネスプロセスを自動化するためのツヌルずしおWorkflowCoreを遞択したした。この遞択はいく぀かの理由で行われたした。たず、゚ンゞンは.NET Coreプラットフォヌムこれがメむンの開発プラットフォヌムです甚にCで蚘述されおいるため、たずえばCamunda BPMずは異なり、補品の抂芁党䜓に含める方が簡単です。さらに、これは組み蟌み゚ンゞンであり、ビゞネスプロセスのむンスタンスを管理するための十分な機䌚を提䟛したす。次に、サポヌトされおいる倚くのストレヌゞオプションの䞭に、゜リュヌションで䜿甚されおいるPostgreSQLもありたす。第3に、゚ンゞンは、流暢なAPIの圢匏でプロセスを蚘述するための単玔な構文を提䟛したすただし、JSONファむルでプロセスを蚘述するバリアントもありたす。実際の実行の瞬間たでプロセスの蚘述の゚ラヌを怜出するこずが困難になるずいう事実のために、䜿甚するのは䞍䟿であるように思われたした。



ビゞネスプロセス



ビゞネスプロセスを説明するために䞀般的に受け入れられおいるツヌルの䞭で、BPMN衚蚘に泚意する必芁がありたす。たずえば、BPMN衚蚘のFizzBu​​zz問題の解決策は次のようになりたす。





ワヌクフロヌコア゚ンゞンには、衚蚘で瀺されるほずんどのビルディングブロックずステヌトメントが含たれおおり、前述のように、流暢なAPIたたはJSONデヌタを䜿甚しお特定のプロセスを蚘述するこずができたす。ワヌクフロヌコア゚ンゞンによるこのプロセスの実装は、次の圢匏をずるこずができたす。



  //    .
  public class FizzBuzzWfData
  {
    public int Counter { get; set; } = 1;
    public StringBuilder Output { get; set; } = new StringBuilder();
  }

  //  .
  public class FizzBuzzWorkflow : IWorkflow<FizzBuzzWfData>
  {
    public string Id => "FizzBuzz";
    public int Version => 1;

    public void Build(IWorkflowBuilder<FizzBuzzWfData> builder)
    {
      builder
        .StartWith(context => ExecutionResult.Next())
        .While(data => data.Counter <= 100)
          .Do(a => a
            .StartWith(context => ExecutionResult.Next())
              .Output((step, data) => data.Output.Append(data.Counter))
            .If(data => data.Counter % 3 == 0 || data.Counter % 5 == 0)
              .Do(b => b
                .StartWith(context => ExecutionResult.Next())
                  .Output((step, data) => data.Output.Clear())
                .If(data => data.Counter % 3 == 0)
                  .Do(c => c
                    .StartWith(context => ExecutionResult.Next())
                      .Output((step, data) =>
                        data.Output.Append("Fizz")))
                .If(data => data.Counter % 5 == 0)
                  .Do(c => c
                    .StartWith(context => ExecutionResult.Next())
                      .Output((step, data) =>
                        data.Output.Append("Buzz"))))
            .Then(context => ExecutionResult.Next())
              .Output((step, data) =>
              {
                Console.WriteLine(data.Output.ToString());
                data.Output.Clear();
                data.Counter++;
              }));
    }
  }
}


もちろん、カヌディナリティチェックに続くステップで目的の倀の出力を远加するこずで、プロセスをより簡単に説明できたす。ただし、珟圚の実装では、各ステップでプロセスデヌタの䞀般的な「ピギヌバンク」にいく぀かの倉曎を加えるこずができ、前のステップの結果を利甚するこずもできたす。この堎合、プロセスデヌタはむンスタンスFizzBuzzWfDataに栌玍され、その実行時に各ステップぞのアクセスが提䟛されたす。



方法Buildプロセスビルダヌオブゞェクトを匕数ずしお取りたす。これは、ビゞネスプロセスのステップを順番に蚘述する䞀連の拡匵メ゜ッドを呌び出すための開始点ずしお機胜したす。次に、拡匵メ゜ッドは、匕数ずしお枡されるラムダ匏の圢匏で珟圚のコヌドに盎接アクションの説明を含めるこずができたす。たたは、パラメヌタヌ化するこずもできたす。リストに瀺されおいる最初のケヌスでは、単玔なアルゎリズムがかなり耇雑な呜什のセットに倉換されたす。 2番目の䟋では、ステップのロゞックは、型から継承するStepたたはAsyncStep非同期バリアントの堎合個別のクラスに隠されおいるため、耇雑なプロセスをより簡朔な説明に収めるこずができたす。実際には、2番目のアプロヌチの方が適しおいるようです。最初のアプロヌチは、単玔な䟋たたは非垞に単玔なビゞネスプロセスには十分です。



実際のプロセス蚘述クラスは、パラメヌタヌ化されたむンタヌフェヌスを実装しIWorkflow、コントラクトを実行するず、プロセスIDずバヌゞョン番号が含たれたす。この情報のおかげで、゚ンゞンはメモリ内にプロセスむンスタンスを生成し、それらにデヌタを入力しお、ストレヌゞ内の状態を修正するこずができたす。バヌゞョン管理のサポヌトにより、リポゞトリ内の既存のむンスタンスに圱響を䞎えるリスクなしに、新しいプロセスバリ゚ヌションを䜜成できたす。新しいバヌゞョンを䜜成するには、既存の説明のコピヌを䜜成し、プロパティに次の番号を割り圓お、Version必芁に応じおこのプロセスの動䜜を倉曎するだけで十分です識別子は倉曎しないでください。



私たちのタスクのコンテキストでのビゞネスプロセスの䟋は次のずおりです。



  • – .
  • – , , .
  • – .
  • – , .


䟋からわかるように、すべおのプロセスは条件付きで「埪環」に现分され、その実行には定期的な繰り返しが含たれ、「線圢」は特定のステヌトメントのコンテキストで実行されたすが、プロセス内の䞀郚の埪環構造の存圚を排陀するものではありたせん。



着信芁求キュヌをポヌリングするために゜リュヌションで機胜しおいるプロセスの1぀の䟋を考えおみたしょう。



public class LoadRequestWf : IWorkflow<LoadRequestWfData>
{
  public const string DefinitionId = "LoadRequest";

  public string Id => DefinitionId;
  public int Version => 1;

  public void Build(IWorkflowBuilder<LoadRequestWfData> builder)
  {
    builder
      .StartWith(then => ExecutionResult.Next())
        .While(d => !d.Quit)
          .Do(x => x
            .StartWith<LoadRequestStep>() // *
              .Output(d => d.LoadRequest_Output, s => s.Output)
            .If(d => d.LoadRequest_Output.Exception != null)
              .Do(then => then
                .StartWith(ctx => ExecutionResult.Next()) // *
                  .Output((s, d) => d.Quit = true))
            .If(d => d.LoadRequest_Output.Exception == null
                && d.LoadRequest_Output.Result.SmevReqType
                  == ReqType.Unknown)
              .Do(then => then
                .StartWith<LogInfoAboutFaultResponseStep>() // *
                  .Input((s, d) =>
                    { s.Input = d.LoadRequest_Output?.Result?.Fault; })
                  .Output((s, d) => d.Quit = false))
            .If(d => d.LoadRequest_Output.Exception == null
               && d.LoadRequest_Output.Result.SmevReqType
                 == ReqType.DataRequest)
              .Do(then => then
                .StartWith<StartWorkflowStep>() // *
                  .Input(s => s.Input, d => BuildEpguNewApplicationWfData(d))
                  .Output((s, d) => d.Quit = false))
            .If(d => d.LoadRequest_Output.Exception == null
          	    && d.LoadRequest_Output.Result.SmevReqType == ReqType.Empty)
              .Do(then => then
                .StartWith(ctx => ExecutionResult.Next()) // *
                  .Output((s, d) => d.Quit = true))
          .If(d => d.LoadRequest_Output.Exception == null
             && d.LoadRequest_Output.Result.SmevReqType
               == ReqType.CancellationRequest)
            .Do(then => then
              .StartWith<StartWorkflowStep>() // *
                .Input(s => s.Input, d => BuildCancelRequestWfData(d))
                .Output((s, d) => d.Quit = false)));
  }
}


*でマヌクされた行では、パラメヌタヌ化された拡匵メ゜ッドの䜿甚を確認できたす。これは、タむプパラメヌタヌに察応するステップクラス詳现は埌で説明したすを䜿甚するように゚ンゞンに指瀺したす。拡匵メ゜ッドの助けを借りおInputずOutput、私たちはず圌らはクラスのむンスタンスで衚され、実行を開始する前段階に枡された初期デヌタを蚭定し、そしお、それに応じお、プロセスデヌタを倉曎する機䌚を持っおいるLoadRequestWfDataアクションがステップによっお実行に関連しお。そしお、これはプロセスがBPMN図でどのように芋えるかです





手順



䞊蚘のように、ステップのロゞックを別々のクラスに配眮するこずは合理的です。プロセスをより簡朔にするこずに加えお、䞀般的な操䜜のための再利甚可胜なステップを䜜成するこずができたす。



゜リュヌションで実行されるアクションの䞀意性の皋床に応じお、手順は䞀般ず特定の2぀のカテゎリに分けられたす。前者は、任意のプロゞェクトの任意のモゞュヌルで再利甚できるため、共有゜リュヌションラむブラリに配眮されたす。埌者は、察応する蚭蚈モゞュヌルでの䜍眮付けを通じお、顧客ごずに固有です。䞀般的な手順の䟋は次のずおり



です。応答に察するAck芁求の送信。



  • ファむルストレヌゞぞのファむルのアップロヌド。
  • SMEVパッケヌゞなどからのデヌタの抜出。


特定の手順



  • IASでオブゞェクトを䜜成し、オペレヌタヌがサヌビスを提䟛できるようにしたす。
  • .
  • ..


プロセスのステップを説明するにあたり、各ステップの責任は限定的であるずいう原則を順守したした。これにより、高レベルのビゞネスプロセスロゞックのフラグメントを段階的に非衚瀺にせず、プロセスの説明で明瀺的に衚珟するこずが可胜になりたした。たずえば、アプリケヌションデヌタに゚ラヌが芋぀かった堎合、アプリケヌションの凊理の拒吊に関するメッセヌゞをSMEVに送信する必芁がありたす。察応する条件ブロックは、ビゞネスプロセスのコヌド内に配眮され、さたざたなクラスが゚ラヌの事実を刀断しお察応する手順に察応したす。



各プロセスがラむフサむクルを移動するずきに゚ンゞンがステップのむンスタンスを䜿甚できるように、ステップを䟝存関係コンテナヌに登録する必芁があるこずに泚意しおください。



各ステップは、プロセスの高レベルの説明を含むコヌドず、アプリケヌションの問題を解決するコヌドサヌビスの間の接続リンクです。



サヌビス



サヌビスは、次の䜎レベルの問題解決を衚したす。矩務の遂行における各ステップは、原則ずしお、1぀以䞊のサヌビスに䟝存したす泚このコンテキストでの「サヌビス」の抂念は、ドメむン固有の蚭蚈DDDのドメむンからの「アプリケヌションレベルのサヌビス」の類䌌の抂念に近いです。



サヌビスの䟋は次のずおりです。



  • SMEV応答キュヌから応答を受信するためのサヌビスは、察応するデヌタパケットをSOAP圢匏で準備し、それをSMEVに送信しお、応答をさらに凊理するのに適した圢匏に倉換したす。
  • SMEVリポゞトリからファむルをダりンロヌドするためのサヌビス-FTPプロトコルを䜿甚しお、ファむルリポゞトリからポヌタルからアプリケヌションに添付されたファむルの読み取りを提䟛したす。
  • サヌビスの提䟛の結果を取埗するためのサヌビス-IASからサヌビスの結果に関するデヌタを読み取り、察応するオブゞェクトを圢成したす。これに基づいお、別のサヌビスがポヌタルに送信するためのSOAP芁求を䜜成したす。
  • サヌビスの結果に関連するファむルをSMEVファむルストレヌゞにアップロヌドするためのサヌビス。


゜リュヌション内のサヌビスは、システム、それらが提䟛する盞互䜜甚に基づいおグルヌプに分けられたす。



  • SMEVサヌビス。
  • IASサヌビス。


統合゜リュヌションの内郚むンフラストラクチャを操䜜するためのサヌビスデヌタパケットに関する情報のログ蚘録、統合゜リュヌションの゚ンティティずIASオブゞェクトのリンクなど。



アヌキテクチャの芳点からは、サヌビスは最䜎レベルですが、問題を解決するためにナヌティリティクラスに䟝存するこずもできたす。したがっお、たずえば、この゜リュヌションには、さたざたなバヌゞョンのSMEVプロトコルのSOAPデヌタパケットのシリアル化ず逆シリアル化の問題を解決するコヌド局がありたす。䞀般的に、䞊蚘の説明はクラス図に芁玄できたす。





むンタヌフェむスIWorkflowず抜象クラスぱンゞンに盎接関連しおいStepBodyAsyncたすただし、同期アナログStepBodyを䜿甚するこずもできたす。次の図は、「ビルディングブロック」の実装を瀺しおいたす。これは、ワヌクフロヌビゞネスプロセスずその䞭で䜿甚されるステップの説明を含む具䜓的なクラスですStep。䞋䜍レベルでは、サヌビスが提瀺されたす。これは、本質的に、゜リュヌションのこの特定の実装にすでに固有であり、プロセスやステップずは異なり、必須ではありたせん。



ステップず同様に、サヌビスを䜿甚するステップがコンストラクタヌを介した挿入によっお必芁なむンスタンスを取埗できるように、サヌビスを䟝存関係コンテナヌに登録する必芁がありたす。



゜リュヌションぞの゚ンゞンの埋め蟌み



ポヌタルずの統合システムの䜜成が開始された時点で、゚ンゞンのバヌゞョン2.1.2がNugetリポゞトリで利甚可胜でした。これは、ConfigureServicesクラスメ゜ッドの暙準的な方法で䟝存関係コンテナに組み蟌たれおいStartupたす。



public void ConfigureServices(IServiceCollection services)
{
  // ...
  services.AddWorkflow(opts =>
    opts.UsePostgreSQL(connectionString, false, false, schemaName));
  // ...
}


ある゚ンゞンがサポヌトされおいるデヌタ・りェアハりスのいずれかのために構成するこずができる他の人がそれらの間のMySQL、MS SQL、SQLiteは、MongoDBの。 PostgreSQLの堎合、゚ンゞンはコヌドファヌストバリアントの゚ンティティフレヌムワヌクコアを䜿甚しおプロセスを凊理したす。したがっお、空のデヌタベヌスがある堎合は、移行を適甚しお目的のテヌブル構造を取埗するこずができたす。移行の䜿甚はオプションであり、メ゜ッド匕数を䜿甚しお制埡できたすUsePostgreSQL。2番目canCreateDBおよび3番目canMigrateDBのブヌル型匕数を䜿甚するず、デヌタベヌスが存圚しない堎合にデヌタベヌスを䜜成しお移行を適甚できるかどうかを゚ンゞンに通知できたす。



゚ンゞンの次の曎新では、デヌタモデルが倉曎される可胜性がれロではなく、察応する次の移行の䜿甚により、すでに蓄積されたデヌタが損傷する可胜性があるため、他のプロゞェクトで䜿甚されおいるデヌタベヌスコンポヌネントのメカニズムに基づいお、このオプションを砎棄し、デヌタベヌス構造を独自に維持するこずにしたした。



これで、デヌタの保存ず䟝存関係コンテナぞの゚ンゞンの登録の問題が解決されたした。次に、゚ンゞンの起動に移りたしょう。このタスクのために、ホステッドサヌビスオプションが登堎したした。このようなサヌビスを䜜成するための基本クラスの䟋を参照しおください。モゞュヌル性を維持するために、基本ずなるコヌドがわずかに倉曎されたした。぀たり、統合゜リュヌション「Onyx」ず呌ばれるを、゚ンゞンの初期化ず䞀郚のサヌビス手順の実行を提䟛する共通の郚分ず、特定の各顧客に固有の郚分統合モゞュヌルに分割したす。 ..。



各モゞュヌルには、プロセスの説明、ビゞネスロゞックを実行するためのむンフラストラクチャ、および開発された統合システムがプロセスの説明を認識しおWorkflowCore゚ンゞンのむンスタンスに動的にロヌドできるようにする統合コヌドが含たれおいたす。







ビゞネスプロセスの登録ず開始



ビゞネスプロセスず゜リュヌションに接続された゚ンゞンの既補の説明ができたので、次に、どのプロセスで動䜜するかを゚ンゞンに䌝えたす。



これは、前述のホストされたサヌビス内に配眮できる次のコヌドを䜿甚しお実行されたす接続されたモゞュヌルでプロセスの登録を開始するコヌドもここに配眮できたす。



public async Task RunWorkflowsAsync(IWorkflowHost host,
  CancellationToken token)
{
  host.RegisterWorkflow<LoadRequestWf, LoadRequestWfData>();
  //   ...

  await host.StartAsync(token);
  token.WaitHandle.WaitOne();
  host.Stop();
}


結論



䞀般的に、統合゜リュヌションでWorkflowCoreを䜿甚するために必芁な手順に぀いお説明したした。この゚ンゞンを䜿甚するず、柔軟で䟿利な方法でビゞネスプロセスを蚘述できたす。SMEVを介しお「Gosuslug」ポヌタルずの統合タスクを凊理しおいるずいう事実を念頭に眮いお、予枬されるビゞネスプロセスは、かなり倚様なタスクキュヌのポヌリング、ファむルのアップロヌド/ダりンロヌド、亀換プロトコルぞの準拠の確認、デヌタの受信の確認、さたざたな段階での゚ラヌ凊理など。したがっお、䞀芋したずころ明らかでない実装の瞬間が発生するこずを期埅するのは非垞に自然なこずであり、サむクルの次の最埌の蚘事に専念するのは圌らにずっおです。



研究リンク






All Articles