diff --git a/buildDownloadZips.txt b/buildDownloadZips.txt index 400f54b9..e6b733e1 100644 --- a/buildDownloadZips.txt +++ b/buildDownloadZips.txt @@ -35,3 +35,4 @@ srcSteps/Frank2Hermes/v500/configurations/hermesBridge configurations/hermesBrid srcSteps/sandbox/v01 sandbox/v01 srcSteps/Frank2Transactions/v480 advancedDevelopmentIntegrationPatternsMessageId messageIdExample srcSteps/Frank2Transactions/v500 advancedDevelopmentDockerDevelPreJms withJms +srcSteps/Frank2Transactions/v510 advancedDevelopmentDockerDevelJms withJms diff --git a/docs/source/advancedDevelopment/dockerDevel/jms.rst b/docs/source/advancedDevelopment/dockerDevel/jms.rst index 1688e955..d1f8b985 100644 --- a/docs/source/advancedDevelopment/dockerDevel/jms.rst +++ b/docs/source/advancedDevelopment/dockerDevel/jms.rst @@ -1,3 +1,5 @@ +*Under construction* + .. _advancedDevelopmentDockerDevelJms: Queues and Java Message Service (JMS) @@ -23,4 +25,4 @@ Second, ``resources.yml`` should be updated so that the Frank!Framework can find The queue is given JNDI name ``qcf-artemis``, the name by which Frank configurations can reference it. The ``type`` field references the Java class that should be used to access the queue. And the ``url`` is needed by the Frank!Framework to reach the queue that is refenced as ``qcf-artemis`` in Frank configurations. Within the value of the ``url`` field, property ``jms.hostname`` is referenced. If the name of the docker container holding the queue is changed, this property should be updated to hold the new name. Because of the property reference, the ``url`` within ``resources.yml`` does not have to be updated in this case. -Above the JMS resource, the JDBC resource is updated to use another database driver, a database driver that supports XA transactions. This is outside the scope of this page. \ No newline at end of file +Above the JMS resource, the JDBC resource is updated to use another database driver, a database driver that supports XA transactions. \ No newline at end of file diff --git a/docs/source/advancedDevelopment/integrationPatterns/errorStoreAndXaTransactions.rst b/docs/source/advancedDevelopment/integrationPatterns/errorStoreAndXaTransactions.rst index 988a8f44..cb73fd14 100644 --- a/docs/source/advancedDevelopment/integrationPatterns/errorStoreAndXaTransactions.rst +++ b/docs/source/advancedDevelopment/integrationPatterns/errorStoreAndXaTransactions.rst @@ -1,6 +1,40 @@ +*Under construction* + .. _advancedDevelopmentIntegrationPatternsErrorStoreXa: Error Store and XA Transactions =============================== -TODO: Explain two phase commit. \ No newline at end of file +This section shows how to implement the Fire and Forget integration pattern using an error storage and a queue. As a starting point, the application created in section :ref:`advancedDevelopmentIntegrationPatternsTransactions` is taken. It is :download:`available for download <../../downloads/advancedDevelopmentDockerDevelPreJms.zip>`. + +Section :ref:`advancedDevelopmentDockerDevelJms` explains how the development environment, files ``docker-compose.yml`` and ``resources.yml``, should be updated to have a queue that can be referenced by Frank configurations. These updates also show that another database driver is needed for PostgreSQL databases that have to support XA transactions. As said, XA transactions are transactions that span multiple data-processing systems, in our case a queue and a database. XA transactions are implemented by the *two phase commit protocol*, see https://en.wikipedia.org/wiki/Two-phase_commit_protocol. This protocol requires a coordinator that drives the data-processing systems. The Frank!Framework uses the Narayana transaction manager for this, which is enabled by setting system property ``transactionmanager.type.default`` to the value ``NARAYANA``. + +With the development environment in place, it can be shown how our example configuration can be updated to have the Fire and Forget integration pattern. The changes are shown below: + +.. literalinclude:: ../../../../srcSteps/Frank2Transactions/v510/src/main/resources/Configuration.xml + :language: xml + :lines: 1-21 + :emphasize-lines: 5, 6, 8, 12, 17, 18, 19 + :linenos: + :append: ... + +Line 5 shows that a new adapter named ``writeDbAsync`` is introduced to hold the ````. It has a ```` that enqueues the incoming message, which is processed by the original adapter that is still named ``writeDb``. Enqueueing is done using a ```` while dequeueing is done using a ```` (lines 12 and 18). These elements are documented in detail in the Frank!Doc. The queue container is accessed using attribute ``queueConnectionFactoryName="jms/qcf-artemis"``. The reference ``jms/qcf-artimis`` is matched in ``resources.yml``, see :ref:`advancedDevelopmentDockerDevelJms`. There is a heading ``jms`` with a list item that has property ``name: "qcf-artemis"``. The ``destinationName`` is the name of the queue being enqueued and dequeued. In our development environment it can be chose freely because we set sysem property ``jms.createDestination`` to ``true``. In production, it is wise to set this property to ``false`` and then only queues configured by the system administrator can be used. + +Preventing that duplicate messages are processed is now done by adapter ``writeDbAsync``. Its receiver has ``checkForDuplicates="true"`` (line 6) and this receiver contains the required message log (line 8). Adapter ``writeDb`` no longer needs a message log because it will not receive duplicate messages anymore. Instead, it has a ```` that will save messages for which processing fails (line 19). The ```` stores the failed messages in database table ``IBISSTORE``. That database table also holds data for other error stores and message logs. Records for this ```` are distinguished because they have the same value for the ``SLOTID`` field; this is configured using the ``slotId`` attribute. Please note that the message log of ``writeDbAsync`` (line 8) and the ```` have a different ``slotId``. + +The ``transactionAttribute`` explained in :ref:`advancedDevelopmentIntegrationPatternsTransactions` works the same for XA transactions as for simple transactions. Adapters ``writeDbAsync`` and ``writeDb`` both have ``transactionAttribute="RequiresNew"``. Enqueueing a message happens in a transaction, so a message is either put in the message log *and* enqueued, or the user gets a negative HTTP response from the ```` and nothing is done. Dequeueing a message happens in another transaction, but that transaction also spans writing the message in the database. A message is either dequeued and processed, or not dequeued at all. + +We do not want that a message appears in the error store already when processing fails once. The Frank!Framework retries processing five times because the receiver of adapter ``writeDb`` (line 17) has ``maxRetries="5"``. In production, the system administrator will have control over the time intervals between the retries, because this is part of configuring the queue. When dequeueing and processing fails repeatedly, the Frank!Framework will put the message in the error store and commit the transaction, causing the message to be dequeued permanently. The service manager can check the error store in the Frank!Console and resend the message when the issue with the application has been fixed. See :ref:`managingProcessedMessagesError`. When the message is resend, the receiver of adapter ``writeDb`` is skipped and the message enters the pipeline directly. The transaction attribute of the receiver is inherited by the pipeline, though. Processing the resent message still happens within a transaction. + +Exercise +-------- + +* Download the :download:`Frank application shown in this section <../../downloads/advancedDevelopmentDockerDevelJms.zip>`. +* Start it using ``docker compose up``. +* Start your API client. The HTTP request of section :ref:`advancedDevelopmentIntegrationPatternsOnlyOnce` applies again, the one with HTTP header for the message id. +* Send the request. Observe that the response is different - nothing about updated database rows now, but a response about the enqueued message. +* Send the same request again. Check that you get a HTTP 304 Not Modified. +* In the Frank!Console, stop adapter ``writeTableOtherMessage``, the adapter that does the second modification of the database. +* Send another message with another value for the message id. Check the messages in the Adapter Status page of the Frank!Console. You should see that processing is retried and that finally the message is written to the error store. +* Start adapter ``writeTableOtherMessage`` and resend the message from the Frank!Console. Check that the message is removed from the error store. +* Using JDBC | Execute Query, check that tables "message" and "otherMessage" now have the message you supplied in the HTTP request. diff --git a/docs/source/advancedDevelopment/integrationPatterns/fireAndForget.rst b/docs/source/advancedDevelopment/integrationPatterns/fireAndForget.rst index 6b1954bc..229d12e5 100644 --- a/docs/source/advancedDevelopment/integrationPatterns/fireAndForget.rst +++ b/docs/source/advancedDevelopment/integrationPatterns/fireAndForget.rst @@ -9,6 +9,6 @@ This section turns to the fire and forget integration pattern introduced in the With the fire and forget integration pattern, messages are often put on a queue. Typically the sender gets a positive response when the request has been put on the queue. The intended recipient reads the request from the queue and processes it. When an error occurs, it may be desirable to roll back reading the request from the queue as well. Then the message can be read again later, hopefully when it can be processed successfully. This can be implemented using XA transactions, transactions that span across multiple data-processing systems, e.g. a queue and a database. Frank developers should also add an error store in this scenario, because processing the request may fail repeatedly. Operators should have a chance to correct errors by hand and then resend failed messages. -An alternative to using a real queue is using the database as a queue. This can be done by sending messages using a ``MessageStoreSender`` and by reading these messages using a ``MessageStoreListener``. The ``MessageStoreSender`` / ``MessageStoreListener`` pair uses database table ``IBISSTORE`` as the queue, which is also used by the ```` introduced in section :ref:`advancedDevelopmentIntegrationPatternsOnlyOnce`. This database-backed queue is insulated from other data in table ``IBISSTORE`` by providing a ``slotId``. All elements of the queue share the same value for the ``slotId`` field within table ``IBISSTORE`` while other data has a different value for this field. +An alternative to using a real queue is using the database as a queue. This can be done by sending messages using a ``MessageStoreSender`` and by reading these messages using a ``MessageStoreListener``. The ``MessageStoreSender`` / ``MessageStoreListener`` pair uses database table ``IBISSTORE`` as the queue, which is also used by the ```` introduced in section :ref:`advancedDevelopmentIntegrationPatternsOnlyOnce`. This database-backed queue is insulated from other data in table ``IBISSTORE`` by providing a ``slotId``. All elements of the queue share the same value for the ``SLOTID`` field within table ``IBISSTORE`` while other data has a different value for this field. When a The ``MessageStoreSender`` / ``MessageStoreListener`` pair is used, the Frank!Framework automatically adds an error store to the Frank!Console. Frank developers do not need to explicitly add an error store to their configuration in this case. Therefore, the examples that will be added in proceeding sections will cover a real queue with an explicit error store before turning to the ``MessageStoreSender`` and the ``MessageStoreListener``. This allows for clear examples to illustrate the concept of an error store. diff --git a/docs/source/downloads/advancedDevelopmentDockerDevelJms.zip b/docs/source/downloads/advancedDevelopmentDockerDevelJms.zip new file mode 100644 index 00000000..ae64d41b Binary files /dev/null and b/docs/source/downloads/advancedDevelopmentDockerDevelJms.zip differ diff --git a/docs/source/downloads/advancedDevelopmentDockerDevelPreJms.zip b/docs/source/downloads/advancedDevelopmentDockerDevelPreJms.zip index 35bdfafa..54d70dbf 100644 Binary files a/docs/source/downloads/advancedDevelopmentDockerDevelPreJms.zip and b/docs/source/downloads/advancedDevelopmentDockerDevelPreJms.zip differ diff --git a/docs/source/downloads/advancedDevelopmentIntegrationPatternsMessageId.zip b/docs/source/downloads/advancedDevelopmentIntegrationPatternsMessageId.zip index a2c7f2c8..18b36e4a 100644 Binary files a/docs/source/downloads/advancedDevelopmentIntegrationPatternsMessageId.zip and b/docs/source/downloads/advancedDevelopmentIntegrationPatternsMessageId.zip differ diff --git a/docs/source/downloads/advancedDevelopmentProperties.zip b/docs/source/downloads/advancedDevelopmentProperties.zip index 6b093a3c..9ca32076 100644 Binary files a/docs/source/downloads/advancedDevelopmentProperties.zip and b/docs/source/downloads/advancedDevelopmentProperties.zip differ diff --git a/docs/source/downloads/configurations/NewHorizons.zip b/docs/source/downloads/configurations/NewHorizons.zip index eed0be22..3eafc8b5 100644 Binary files a/docs/source/downloads/configurations/NewHorizons.zip and b/docs/source/downloads/configurations/NewHorizons.zip differ diff --git a/docs/source/downloads/configurations/NewHorizonsDatabase.zip b/docs/source/downloads/configurations/NewHorizonsDatabase.zip index 1a3233a7..6ea94b2d 100644 Binary files a/docs/source/downloads/configurations/NewHorizonsDatabase.zip and b/docs/source/downloads/configurations/NewHorizonsDatabase.zip differ diff --git a/docs/source/downloads/configurations/NewHorizonsOnlyTableBooking.zip b/docs/source/downloads/configurations/NewHorizonsOnlyTableBooking.zip index 8e43fe06..9861ca7e 100644 Binary files a/docs/source/downloads/configurations/NewHorizonsOnlyTableBooking.zip and b/docs/source/downloads/configurations/NewHorizonsOnlyTableBooking.zip differ diff --git a/docs/source/downloads/configurations/NewHorizonsValidate.zip b/docs/source/downloads/configurations/NewHorizonsValidate.zip index 0fb537e8..b64bbb47 100644 Binary files a/docs/source/downloads/configurations/NewHorizonsValidate.zip and b/docs/source/downloads/configurations/NewHorizonsValidate.zip differ diff --git a/docs/source/downloads/configurations/credentials.zip b/docs/source/downloads/configurations/credentials.zip index e86c74a9..d5ae903e 100644 Binary files a/docs/source/downloads/configurations/credentials.zip and b/docs/source/downloads/configurations/credentials.zip differ diff --git a/docs/source/downloads/configurations/forFrankConsole.zip b/docs/source/downloads/configurations/forFrankConsole.zip index 3c75c81d..c1ee5f9c 100644 Binary files a/docs/source/downloads/configurations/forFrankConsole.zip and b/docs/source/downloads/configurations/forFrankConsole.zip differ diff --git a/docs/source/downloads/configurations/forFrankConsole_2.zip b/docs/source/downloads/configurations/forFrankConsole_2.zip index d0aa10b3..cb6f92d8 100644 Binary files a/docs/source/downloads/configurations/forFrankConsole_2.zip and b/docs/source/downloads/configurations/forFrankConsole_2.zip differ diff --git a/docs/source/downloads/configurations/hermesBridge.zip b/docs/source/downloads/configurations/hermesBridge.zip index e1652208..1e58359c 100644 Binary files a/docs/source/downloads/configurations/hermesBridge.zip and b/docs/source/downloads/configurations/hermesBridge.zip differ diff --git a/docs/source/downloads/deploymentTomcat.zip b/docs/source/downloads/deploymentTomcat.zip index 129f95e4..fbe76263 100644 Binary files a/docs/source/downloads/deploymentTomcat.zip and b/docs/source/downloads/deploymentTomcat.zip differ diff --git a/docs/source/downloads/extendLadybugTable.zip b/docs/source/downloads/extendLadybugTable.zip index 8e1b2304..428883da 100644 Binary files a/docs/source/downloads/extendLadybugTable.zip and b/docs/source/downloads/extendLadybugTable.zip differ diff --git a/docs/source/downloads/ladybug.zip b/docs/source/downloads/ladybug.zip index f2e82ec5..6b556dff 100644 Binary files a/docs/source/downloads/ladybug.zip and b/docs/source/downloads/ladybug.zip differ diff --git a/docs/source/downloads/sandbox/v01.zip b/docs/source/downloads/sandbox/v01.zip index 174b6485..63edc2c0 100644 Binary files a/docs/source/downloads/sandbox/v01.zip and b/docs/source/downloads/sandbox/v01.zip differ