-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #301 from navikt/sf-pdl-kafka
Sf pdl kafka
- Loading branch information
Showing
112 changed files
with
4,215 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,5 +50,6 @@ install.cmd | |
|
||
# misc | ||
.*.sw? | ||
*.vim | ||
TAGS | ||
tags |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
{ | ||
"plugins": ["prettier-plugin-apex"], | ||
"trailingComma": "none", | ||
"printWidth": 120, | ||
"singleQuote": true, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,73 @@ | ||
# crm-platform-integration | ||
|
||
This package contains the `KafkaMessage__c` sObject and related Apex logic in order to receive JSON payloads representing | ||
changes from the Kafka CDC pipeline. A trigger on the `KafkaMessage__c` sObject will create enqueue asynchronous processing | ||
request through the asynchronous processing framework that is part of the crm-platform-base package. | ||
This package contains the `KafkaMessage__c` sObject and related Apex logic in | ||
order to receive JSON payloads representing changes from the Kafka CDC pipeline. | ||
A trigger on the `KafkaMessage__c` sObject will enqueue asynchronous processing | ||
requests through the asynchronous processing framework that is part of the | ||
**crm-platform-base** package. | ||
|
||
## Custom Metadata Bindings | ||
|
||
The framework depends on two custom metadata objects in order to dynamically instruct the application how to handle the message payload. | ||
The framework depends on two custom metadata objects in order to dynamically | ||
instruct the application how to handle the message payload. | ||
|
||
### AsyncRequestHandlerBinding_mdt | ||
### `AsyncRequestHandlerBinding__mdt` | ||
|
||
Binding between the asynchronous processing request (`AsyncRequest__c`) type created by this package and the `KafkaMessageAsyncJob` class | ||
in order to instruct the asynchronous processing framework to call the `KafkaMessageAsyncJob` class in order to handle | ||
requests originating from this package. | ||
Binding between the asynchronous processing request (`AsyncRequest__c`) type | ||
created by this package and the `KafkaMessageAsyncJob` class in order to | ||
instruct the asynchronous processing framework to call the | ||
`KafkaMessageAsyncJob` class in order to handle requests originating from this | ||
package. | ||
|
||
### KafkaMessageHandlerBinding_mdt | ||
### `KafkaMessageHandlerBinding__mdt` | ||
|
||
Binding between the KafkaMessage**c.Topic**c field and an Apex handler class for a given Topic in order to instruct the | ||
application on how to handle a message payload related to a specific Kafka topic. | ||
Binding between the `KafkaMessage__c.Topic__c` field and an Apex handler class | ||
for a given Topic in order to instruct the application on how to handle a | ||
message payload related to a specific Kafka topic. | ||
|
||
## Execution Flow | ||
|
||
1. An external application inserts a record or batch or records into the KafkaMessage\_\_c sObject | ||
2. A trigger on the KafkaMessage**c object insert one record into the AsyncRequest**c object for each batch of up to 200 | ||
KafkaMessage\_\_c records created in a single transaction, representing a a request for asynchronous processing of the new | ||
messages. | ||
3. When the asynchronous processing framework processes the request, the custom metadata binding `AsyncRequestHandlerBinding_mdt` | ||
instructs the application to handle the request using the `KafkaMessageAsyncJob` Apex class. - If no `AsyncRequestHandlerBinding_mdt` record is found corresponding to the "Kafka Message" AsyncRequestType**c value, | ||
the `AsyncRequest**c` record is updated with an error. | ||
4. The `KafkaMessageAsyncJob` queries for the relevant KafkaMessage**c records by the Ids stored in the async processing | ||
request and queries the `KafkaMessageHandlerBinding_mdt` custom metadata object for registered bindings between `KafkaMessage**c.Topic**c` | ||
values and corresponding Apex classes to handle payloads corresponding to Topic**c values. - If no `KafkaMessageHandlerBinding_mdt` record is found corresponding to the `Topic__c` value, the relevant | ||
`KafkaMessage__c` record is updated with an error. The message kan then be retried after the error has been addressed. | ||
5. The Apex class registered by the `KafkaMessageHandlerBinding_mdt` binding executes the business logic corresponding to the | ||
`Topic__c` value. - If an execption occurs, the relevant`KafkaMessage__c` record is updated with an error. The message kan then be retried | ||
after the error has been addressed. | ||
|
||
1. An external application inserts a record or batch or records into the | ||
`KafkaMessage__c` sObject | ||
2. A trigger on the `KafkaMessage__c` object insert one record into the | ||
`AsyncRequest__c` object for each batch of up to 200 `KafkaMessage__c` | ||
records created in a single transaction, representing a request for | ||
asynchronous processing of the new messages. | ||
3. When the asynchronous processing framework processes the request, the custom | ||
metadata binding `AsyncRequestHandlerBinding__mdt` instructs the application | ||
to handle the request using the `KafkaMessageAsyncJob` Apex class. - If no | ||
`AsyncRequestHandlerBinding__mdt` record is found corresponding to the "Kafka | ||
Message" `AsyncRequestType__c` value, the `AsyncRequest__c` record is updated | ||
with an error. | ||
4. The `KafkaMessageAsyncJob` queries for the relevant `KafkaMessage__c` records | ||
by the Ids stored in the async processing request and queries the | ||
`KafkaMessageHandlerBinding__mdt` custom metadata object for registered | ||
bindings between `KafkaMessage__c.Topic__c` values and corresponding Apex | ||
classes to handle payloads corresponding to `Topic__c` values. - If no | ||
`KafkaMessageHandlerBinding__mdt` record is found corresponding to the | ||
`Topic__c` value, the relevant `KafkaMessage__c` record is updated with an | ||
error. The message can then be retried after the error has been addressed. | ||
i. If `KafkaMessageHandlerBinding__mdt.SandboxOverrideTopic__c` exists, it is | ||
its value which will correspond with `KafkaMessage__c.Topic__c` in scratch | ||
orgs and sandboxes. `KafkaMessageHandlerBinding__mdt.Topic__c` will in this | ||
case remain unused. | ||
5. The Apex class registered by the `KafkaMessageHandlerBinding__mdt` binding | ||
executes the business logic corresponding to the `Topic__c` value. If an | ||
exception occurs, the relevant `KafkaMessage__c` record is updated with an | ||
error. The message can then be retried after the error has been addressed. | ||
|
||
## Synchronous kafka message handling | ||
|
||
To process incoming kafka messages in a synchronous context the following pattern should be followed: | ||
1. Definition of a separate platform event with the exact data model as i.e. defined [here](https://github.com/navikt/crm-platform-oppgave/tree/master/force-app/main/default/objects/Kafka_Oppgave_Event__e). | ||
To process incoming kafka messages in a synchronous context the following | ||
pattern should be followed: | ||
1. Definition of a separate platform event with the exact data model as i.e. | ||
defined | ||
[here](https://github.com/navikt/crm-platform-oppgave/tree/master/force-app/main/default/objects/Kafka_Oppgave_Event__e). | ||
2. Create a trigger and separate trigger handler to process the incoming events. | ||
3. The processing itself should be implemented using the IKafkaMessageConsumer interface such that error handling can be performed easily storing failed events as KafkaMessage__c records. An example of this can be veiwed [here](https://github.com/navikt/crm-platform-oppgave/blob/master/force-app/main/default/classes/kafka/CRM_KafkaOppgaveEventHandler.cls) where *doEventTransform* performs the transformation from the custom event to the KafkaMessage__c model and the failed events are stored as KafkaMessage__c records in an error status. | ||
3. The processing itself should be implemented using the `IKafkaMessageConsumer` | ||
interface such that error handling can be performed easily storing failed | ||
events as `KafkaMessage__c` records. An example of this can be viewed | ||
[here](https://github.com/navikt/crm-platform-oppgave/blob/master/force-app/main/default/classes/kafka/CRM_KafkaOppgaveEventHandler.cls) | ||
where *doEventTransform* performs the transformation from the custom event to | ||
the `KafkaMessage__c` model and the failed events are stored as | ||
`KafkaMessage__c` records in an error status. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
//Start executing AsyncRequests => Trigger handle the KafkaMessages | ||
Database.executeBatch(new AsyncRequestBatchable(),50); | ||
Database.executeBatch(new AsyncRequestBatchable(),50); |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
force-app/main/default/classes/KafkaMessageHandlerTest.cls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* Tests methods specific to KafkaMessageHandler. See KafkaMessageServiceTest | ||
* for similar tests. | ||
*/ | ||
@IsTest | ||
public with sharing class KafkaMessageHandlerTest { | ||
/** | ||
* Tests that the topic given in SandboxOverrideTopic__c is picked up by the | ||
* handler. KafkaMessageHandlerBinding__mdt can not be modified in tests, so | ||
* we assume the values are set correctly; CRM_Priority__c is set to 20 by | ||
* default, but to 19 where the SandboxOverrideTopic__c matches the topic | ||
* given here. | ||
*/ | ||
@IsTest | ||
private static void handleSandboxOverrideTopicPriority() { | ||
// These topics will only be picked up in sandboxes, so only run there. | ||
if ([SELECT IsSandbox FROM Organization][0].IsSandbox) { | ||
KafkaMessage__c msg = new KafkaMessage__c( | ||
CRM_Key__c = '1792160394037', | ||
CRM_Topic__c = 'pdl.pdl-persondokument-tagged-v1', | ||
CRM_Value__c = null | ||
); | ||
insert msg; | ||
Test.startTest(); | ||
new KafkaMessageService(new List<KafkaMessage__c>{ msg }).handleMessages(); | ||
Test.stopTest(); | ||
System.assertEquals( | ||
KafkaMessageService.STATUS_PROCESSED, | ||
[SELECT Id, CRM_Status__c FROM KafkaMessage__c WHERE Id = :msg.Id LIMIT 1].CRM_Status__c | ||
); | ||
System.assertEquals(19, [SELECT CRM_Priority__c FROM AsyncRequest__c LIMIT 1].CRM_Priority__c); | ||
} | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
force-app/main/default/classes/KafkaMessageHandlerTest.cls-meta.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>59.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
...ult/objects/KafkaMessageHandlerBinding__mdt/fields/SandboxOverrideTopic__c.field-meta.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<fullName>SandboxOverrideTopic__c</fullName> | ||
<description>Overrides Topic__c when in a sandbox</description> | ||
<externalId>false</externalId> | ||
<fieldManageability>DeveloperControlled</fieldManageability> | ||
<inlineHelpText>When it is not desirable that all events on the topic given in Topic__c is consumed in a sandbox, this field specifies an alternative topic.</inlineHelpText> | ||
<label>Sandbox Override Topic</label> | ||
<length>255</length> | ||
<required>false</required> | ||
<type>Text</type> | ||
<unique>false</unique> | ||
</CustomField> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.