ビジネス イベント、カスタム メッセージ キュー、カスタム メッセージ タイプ

この記事では、Visual Studioを使用して、message プロセッサの独自のカスタム メッセージ キューとメッセージの種類を設計する方法について説明します。 また、失敗した処理結果のアラートを配信するようにビジネス イベントを設定する方法についても説明します。

失敗した処理結果に対する警告を配信するビジネス イベントの設定

失敗した処理結果について警告する ビジネス イベント を設定できます。 この設定を完了するには、ビジネス イベント カタログ ページで メッセージ プロセッサ メッセージ処理 ビジネス イベントを有効化します (システム管理 > 設定 > ビジネス イベント > ビジネス イベント カタログ)。 アクティブ化プロセスの一環として、イベントが特定の法人に固有であるか、すべての法人に適用するかを指定するように求められます。 また、エンドポイント名を指定して事前に定義する必要があります。

Note

ビジネス イベントが発生した場合 が (たとえば HTTPS ではなく) Microsoft Power Automate に設定されている場合、エンドポイント名は Microsoft Power Automate の設定に基づいて サプライ チェーン管理 で自動的に作成されます。

ビジネス イベントの Power Automate の例

この例では、ビジネス イベントが発生するとMicrosoft Power Automate に設定され、アクション センター (旧称 Infolog) メッセージと、特定の失敗したメッセージの Message プロセッサ メッセージ ページを開くハイパーリンクを含む電子メール通知を送信します。 必要に応じて、異なるチャネルを使用して並列で通知を送信し、イベント データに基づく受信者を制御する追加ロジックを追加することができます。

  1. Power Automate で、ビジネス イベントが発生した場合 - Fin & Ops App (Dynamics 365) フロー トリガー用の自動クラウド フローを作成し、その後に JSON の解析メールの送信 のステップを追加します。

    Power Automate の自動クラウド フロー.

  2. ビジネス イベントの発生時 ステップでは、インスタンス フィールドと カテゴリ フィールドで値を検索または入力し、ビジネス イベント フィールドを 処理されたメッセージ プロセッサのメッセージ に設定します。

    Power Automate の [ビジネス イベントが発生したとき] ステップ。

  3. JSON の解析 のステップで、スキーマ フィールドで、拡張フィールドを定義するスキーマを入力します。 サプライ チェーン管理 の ビジネス イベント カタログ ページにある スキーマのダウンロード オプションを使用するか、または例にあるスキーマ テキストを貼り付けて開始することができます。

    {
        "properties": {
            "BusinessEventId": {
                "type": "string"
            },
            "ControlNumber": {
                "type": "integer"
            },
            "EventId": {
                "type": "string"
            },
            "EventTime": {
                "type": "string"
            },
            "MajorVersion": {
                "type": "integer"
            },
            "MessageContent": {
                "type": "string"
            },
            "MessageDestinationCompanyId": {
                "type": "string"
            },
            "MessageDestinationOperationalSiteId": {
                "type": "string"
            },
            "MessageDestinationWarehouseId": {
                "type": "string"
            },
            "MessageDestinationWorkloadName": {
                "type": "string"
            },
            "MessageInfolog": {
                "type": "string"
            },
            "MessageProcessingResult": {
                "type": "string"
            },
            "MessageProcessingResultLabel": {
                "type": "string"
            },
            "MessageProcessorMessagePageUrl": {
                "type": "string"
            },
            "MessageQueue": {
                "type": "string"
            },
            "MessageQueueLabel": {
                "type": "string"
            },
            "MessageSourceCompanyId": {
                "type": "string"
            },
            "MessageSourceOperationalSiteId": {
                "type": "string"
            },
            "MessageSourceWarehouseId": {
                "type": "string"
            },
            "MessageSourceWorkloadName": {
                "type": "string"
            },
            "MessageState": {
                "type": "string"
            },
            "MessageStateLabel": {
                "type": "string"
            },
            "MessageType": {
                "type": "string"
            },
            "MessageTypeLabel": {
                "type": "string"
            },
            "MinorVersion": {
                "type": "integer"
            }
        },
        "type": "object"
    }
    

    Power Automate の JSON の解析ステップ。

  4. 電子メールの送信 ステップにおいて、個別のフィールドを選択するか、または電子メール本文の例を 本文 フィールドに貼り付けて開始することができます。

    Message queue: @{body('Parse_JSON')?['MessageQueue']}
    Message queue label: @{body('Parse_JSON')?['MessageQueueLabel']}
    Message type: @{body('Parse_JSON')?['MessageQueueType']}
    Message type label: @{body('Parse_JSON')?['MessageQueueTypeLabel']}
    Message content: @{body('Parse_JSON')?['MessageContent']}
    Message state: @{body('Parse_JSON')?['MessageState']}
    Message state label: @{body('Parse_JSON')?['MessageStateLabel']}
    Message processing result: @{body('Parse_JSON')?['MessageProcessingResult']}
    Message processing result label: @{body('Parse_JSON')?['MessageProcessingResultLabel']}
    Message infolog: @{body('Parse_JSON')?['MessageInfolog']}
    Message source company ID: @{body('Parse_JSON')?['MessageSourceCompanyId']}
    Message source workload name: @{body('Parse_JSON')?['MessageSourceWorkloadName']}
    Message source site ID: @{body('Parse_JSON')?['MessageSourceOperationalSiteId']}
    Message source warehouse ID: @{body('Parse_JSON')?['MessageSourceWarehouseId']}
    Message destination company ID: @{body('Parse_JSON')?['MessageDestinationCompanyId']}
    Message destination workload name: @{body('Parse_JSON')?['MessageDestinationWorkloadName']}
    Message destination site ID: @{body('Parse_JSON')?['MessageDestinationOperationalSiteId']}
    Message destination warehouse ID: @{body('Parse_JSON')?['MessageDestinationWarehouseId']}
    Message processor message page URL: @{body('Parse_JSON')?['MessageProcessorMessagePageUrl']}
    

    Power Automate のメール送信ステップ。

ビジネス イベントを保存すると自動的に有効化され、サプライ チェーン管理 の一部として使用可能になります。

メッセージ プロセッサ スケジューラ

メッセージ プロセッサには、1 つのスケジューラがあります。 SysMessageKeyDateTimeSequenceProcessorScheduler クラスは、キー、日付、および時刻に基づく依存関係を持つメッセージをスケジュールして、メッセージが正しい順序で処理されます。 処理する必要があるメッセージは、SysMessageProcessorTaskBundle テーブルと SysMessageProcessorTaskBundleMessage テーブルに格納されます。 依存メッセージは同じバンドルに含む必要があります。

SysMessageKeyDateTimeSequenceProcessorScheduler クラスは、サードパーティの MES 統合 機能によって使用され、生産オーダーに関連するメッセージを保護し、受信または作成された順番に処理されます。 この依存関係は、キー (製造オーダー番号) と時刻で定義されます。

たとえば、システムは次のメッセージを受信または作成します:

  • 製造オーダー 1 - メッセージの開始
  • 製造オーダー 2 - メッセージの開始
  • 製造オーダー 2 - 終了メッセージとして報告
  • 製造オーダー 1 - 終了メッセージとして報告

この場合、SysMessageKeyDateTimeSequenceProcessorScheduler クラスは以下の順序でメッセージの処理をスケジューリングします:

  1. 製造オーダー 1 - メッセージの開始
  2. 製造オーダー 1 - 終了メッセージとして報告
  3. 製造オーダー 2 - メッセージの開始
  4. 製造オーダー 2 - 終了メッセージとして報告

各完了レポート メッセージは、関連する開始メッセージが正常に処理されたかどうかに依存します。

ボトルネックが発生する場合は、複数のタスクの処理用にレコードを取得するときにボトルネックが発生する可能性があります。また、メッセージ間に依存関係がある可能性があるから、システムはメッセージをバンドルします。 たとえば、バンドル サイズが 2 の場合、次のバンドルが作成されます:

  • バンドル 1 - 製造オーダー 1 - メッセージの開始
  • バンドル 1 - 製造オーダー 1 - メッセージの開始
  • バンドル 2 - 製造オーダー 2 - メッセージの開始
  • バンドル 2 - 製造オーダー 2 - メッセージの開始

スケーラビリティについては、新しいキューを作成するときに、バンドルを処理する必要があるタスクの数を構成できます。 (詳細については、 新しいキューの実装に関するページを参照してください)。構成で 2 つのメッセージ プロセッサ タスクを使用する場合、2 つのバンドルを並列で処理できます。

開発例: カスタム メッセージ キューを実装する

この例では、新規キューを追加する方法も示します。 キューが作成された後、キューにメッセージを送信できます。 これらのメッセージは、前述の設定に従ってメッセージ プロセッサによって処理されます。

  1. Visual Studioで、SysMessageQueue 列挙型の拡張機能を作成します。

  2. 新しいキューの新しい列挙値を追加します。

    新しいキューの新しい列挙値を追加する。

  3. 列挙値の機能クラスを設定します。

    列挙値に対するフィーチャクラスの設定。

  4. 次の例に示すように、SysMessageQueueMetadata を継承したクラスを作成します。

    [SysMessageQueueFactoryAttribute(SysMessageQueue::MyQueue)]
    public final class MyQueue extends SysMessageQueueMetadata
    {
    
        /// <summary>
        /// Gets the default number of message processor tasks.
        /// </summary>
        /// <returns>The default number of message processor tasks.</returns>
        public SysMessageProcessorsTasks getDefaultMessageProcessorsTasks()
        {
            return 1;
        }
    
        /// <summary>
        /// Get the maximum number of messages in a bundle.
        /// </summary>
        /// <returns>The maximum number of messages in a bundle.</returns>
        public SysMessageProcessorMaxBundleSize getMaxBundleSize()
        {
            return 10;
        }
    
        /// <summary>
        /// Determines if messages should be queued when sending or processing messages.
        /// </summary>
        /// <returns>true if messages should be queued when sending a message; otherwise false.</returns>
        public boolean queueMessageOnSend()
        {
            return true;
        }
    
        /// <summary>
        /// Determines if dependent messages should be committed per created transaction ID.
        /// </summary>
        /// <returns>true if dependent messages should be committed per created transaction ID.; otherwise false.</returns>
        public boolean commitPerCreatedTransactionID()
        {
            return false;
        }
    }
    

開発例: カスタム メッセージの種類を実装する

この例では、メッセージ プロセッサで使用するプロセスのタイプごとにメッセージ タイプを作成する方法を示します。 メッセージ タイプによって、そのタイプのメッセージによって実行できるプロセスが指定されます。 キュー内の各メッセージの目的を識別するために、メッセージのタイプ名が メッセージ プロセッサ メッセージ ページに表示されます。

以下の手順に従って、新しいメッセージ タイプを作成してください。

  1. Visual Studioで、SysMessageType 列挙型の拡張機能を作成します。

  2. 新しいメッセージ タイプの新しい列挙値を追加します。

    新しいメッセージの種類に新しい列挙値を追加する。する

  3. 列挙値の機能クラスを設定します。

    列挙型の値にフィーチャクラスを設定します。

  4. 次の例に示すように、SysMessageTypeMetadata を継承したクラスを作成します。

    [SysMessageTypeFactoryAttribute(SysMessageType::MyMessage)]
    public final class MyMessage extends SysMessageTypeMetadata
    {
        /// <summary>
        /// Validates if it is allowed to send a message on a given queue.
        /// </summary>
        /// <param name = "_messageQueue">A queue to send message to.</param>
        /// <param name = "_messageTarget">A message target.</param>
        /// <param name = "_sourceMessageTarget">A message source.</param>
        /// <returns>true if it is allowed to send a message; false, otherwise.</returns>
        public boolean canSendMessage(SysMessageQueue _messageQueue, SysMessageTargetRecId _messageTarget, SysMessageTargetRecId _sourceMessageTarget)
        {
            if (_messageQueue == SysMessageQueue::MyQueue)
            {
                return true;
            }
    
            return false;
        }
    
        /// <summary>
        /// Returns a list of allowed message state transitions.
        /// </summary>
        /// <returns>A list of allowed message state transitions.</returns>
        public Enumerator getAllowedMessageStateTransitions()
        {
            // Allow the following state transitions:
    
            // SysMessageState::None -> SysMessageState::Queued
            // SysMessageState::None -> SysMessageState::Processed
    
            // SysMessageState::Queued -> SysMessageState::Processed
    
            // SysMessageState::Failed -> SysMessageState::Queued
            // SysMessageState::Failed -> SysMessageState::Cancelled
            // SysMessageState::Failed -> SysMessageState::Processed
    
            return SysMessageStateTransition::getProcessedCancelledStateTransitions();
        }
    
        /// <summary>
        /// Returns dependencies related to a message.
        /// </summary>
        /// <param name = "_message">The message to add dependencies to.</param>
        /// <returns>A list of dependencies related to a message.</returns>
        public List getDependencies(SysMessage _message)
        {
            List dependencies = new List(Types::Record);
    
            // Add a dependency to the message if you need to process messages in order. 
            // For example, process a start message before an end message. 
            // The message will not be processed before the dependent message is processed or cancelled.
    
            // The default scheduler, SysMessageKeyDateTimeSequenceProcessorScheduler only supports one dependency per message.
            // Messages with different keys may be processed in parallel.
    
            SysMessageDependencyKey dependencyKey = strFmt('Mykey:%1', this.getContract(_message).parmMyKey());
            dependencies.addEnd(SysMessageKeyDateTimeSequenceDependency::create(dependencyKey));
    
            return dependencies;
        }
    
        /// <summary>
        /// Execute the logic associated with the given message state transition.
        /// </summary>
        /// <param name = "_message">The message.</param>
        /// <param name = "_messageStateTransition">The state transition to execute.</param>
        public void processMessageStateTransition(SysMessage _message, SysMessageStateTransition _messageStateTransition)
        {
            if (_messageStateTransition.isEqual(SysMessageStateTransition::newFromStates(SysMessageState::Queued, SysMessageState::Processed)))
            {
                this.processMessage(_message);
            }
            else if (_messageStateTransition.isEqual(SysMessageStateTransition::newFromStates(SysMessageState::Failed, SysMessageState::Processed)))
            {
                this.cancelMessage(_message);
            }
        }
    
        private void processMessage(SysMessage _message)
        {
            // Add logic to process the message.
        }
    
        private void cancelMessage(SysMessage _message)
        {
            // Add logic to cancel the message if needed.
        }
    
        private ClassId contractClass()
        {
            return classNum(MyContract);
        }
    
        protected MyContract getContract(SysMessage _message, ClassId _objectTypeId = this.contractClass())
        {
            var contract = FormJsonSerializer::deserializeObject(_objectTypeId, _message.Content) as MyContract;
    
            return contract;
        }
    
    }