11package org .folio .search .integration .message ;
22
3- import static org .apache .commons .collections4 .MapUtils .getString ;
4- import static org .apache .commons .lang3 .RegExUtils .replaceAll ;
53import static org .folio .search .configuration .RetryTemplateConfiguration .KAFKA_RETRY_TEMPLATE_NAME ;
64import static org .folio .search .configuration .SearchCacheNames .REFERENCE_DATA_CACHE ;
7- import static org .folio .search .domain .dto .ResourceEventType .CREATE ;
85import static org .folio .search .domain .dto .ResourceEventType .DELETE ;
9- import static org .folio .search .domain .dto .ResourceEventType .REINDEX ;
10- import static org .folio .search .utils .SearchConverterUtils .getEventPayload ;
116import static org .folio .search .utils .SearchConverterUtils .getResourceEventId ;
127import static org .folio .search .utils .SearchConverterUtils .getResourceSource ;
13- import static org .folio .search .utils .SearchUtils .ID_FIELD ;
14- import static org .folio .search .utils .SearchUtils .INSTANCE_ID_FIELD ;
158import static org .folio .search .utils .SearchUtils .SOURCE_CONSORTIUM_PREFIX ;
169
1710import java .util .List ;
18- import java .util .Objects ;
1911import java .util .function .Consumer ;
2012import java .util .function .Predicate ;
2113import java .util .stream .Collectors ;
2517import org .apache .kafka .clients .consumer .ConsumerRecord ;
2618import org .apache .logging .log4j .message .FormattedMessage ;
2719import org .folio .search .domain .dto .ResourceEvent ;
20+ import org .folio .search .model .event .IndexInstanceEvent ;
2821import org .folio .search .model .types .ResourceType ;
2922import org .folio .search .service .ResourceService ;
3023import org .folio .search .service .config .ConfigSynchronizationService ;
3326import org .folio .spring .service .SystemUserScopedExecutionService ;
3427import org .springframework .cache .annotation .CacheEvict ;
3528import org .springframework .kafka .annotation .KafkaListener ;
29+ import org .springframework .kafka .core .KafkaTemplate ;
3630import org .springframework .stereotype .Component ;
3731
3832/**
@@ -47,6 +41,8 @@ public class KafkaMessageListener {
4741 private final FolioMessageBatchProcessor folioMessageBatchProcessor ;
4842 private final SystemUserScopedExecutionService executionService ;
4943 private final ConfigSynchronizationService configSynchronizationService ;
44+ private final KafkaTemplate <String , IndexInstanceEvent > instanceEventProducer ;
45+ private final InstanceEventMapper instanceEventMapper ;
5046
5147 /**
5248 * Handles instance events and indexes them by id.
@@ -61,14 +57,36 @@ public class KafkaMessageListener {
6157 concurrency = "#{folioKafkaProperties.listener['events'].concurrency}" )
6258 public void handleInstanceEvents (List <ConsumerRecord <String , ResourceEvent >> consumerRecords ) {
6359 log .info ("Processing instance related events from kafka events [number of events: {}]" , consumerRecords .size ());
64- var batch = getInstanceResourceEvents (consumerRecords );
65- var batchByTenant = batch .stream ().collect (Collectors .groupingBy (ResourceEvent ::getTenant ));
60+ consumerRecords .stream ().collect (Collectors .groupingBy (consumerRecord -> consumerRecord .value ().getTenant ()))
61+ .forEach ((tenant , records ) -> executionService .executeSystemUserScoped (tenant , () -> {
62+ records .stream ()
63+ .map (instanceEventMapper ::mapToProducerRecords )
64+ .flatMap (List ::stream )
65+ .forEach (instanceEventProducer ::send );
66+ return null ;
67+ }));
68+ }
69+
70+ /**
71+ * Handles instance events and indexes them by id.
72+ *
73+ * @param consumerRecords - list of consumer records from Apache Kafka to process.
74+ */
75+ @ KafkaListener (
76+ id = KafkaConstants .INDEX_INSTANCE_LISTENER_ID ,
77+ containerFactory = "indexInstanceListenerContainerFactory" ,
78+ topicPattern = "#{folioKafkaProperties.listener['index-instance'].topicPattern}" ,
79+ groupId = "#{folioKafkaProperties.listener['index-instance'].groupId}" ,
80+ concurrency = "#{folioKafkaProperties.listener['index-instance'].concurrency}" )
81+ public void handleIndexInstanceEvents (List <ConsumerRecord <String , IndexInstanceEvent >> consumerRecords ) {
82+ log .info ("Processing index instance events from kafka [number of events: {}]" , consumerRecords .size ());
83+ var batchByTenant = consumerRecords .stream ().map (ConsumerRecord ::value )
84+ .collect (Collectors .groupingBy (IndexInstanceEvent ::tenant ));
6685 batchByTenant .forEach ((tenant , resourceEvents ) -> executionService .executeSystemUserScoped (tenant , () -> {
6786 folioMessageBatchProcessor .consumeBatchWithFallback (resourceEvents , KAFKA_RETRY_TEMPLATE_NAME ,
68- resourceService ::indexInstancesById , KafkaMessageListener ::logFailedEvent );
87+ resourceService ::indexInstanceEvents , KafkaMessageListener ::logFailedEvent );
6988 return null ;
7089 }));
71-
7290 }
7391
7492 /**
@@ -164,38 +182,6 @@ private void indexResources(List<ResourceEvent> batch, Consumer<List<ResourceEve
164182 }));
165183 }
166184
167- private static List <ResourceEvent > getInstanceResourceEvents (List <ConsumerRecord <String , ResourceEvent >> events ) {
168- return events .stream ()
169- .map (KafkaMessageListener ::getInstanceResourceEvent )
170- .filter (Objects ::nonNull )
171- .distinct ()
172- .toList ();
173- }
174-
175- private static ResourceEvent getInstanceResourceEvent (ConsumerRecord <String , ResourceEvent > consumerRecord ) {
176- var instanceId = getInstanceId (consumerRecord );
177- var value = consumerRecord .value ();
178- if (instanceId == null ) {
179- log .warn ("Failed to find instance id in record [record: {}]" , replaceAll (value .toString (), "\\ s+" , " " ));
180- return null ;
181- }
182- var operation = isInstanceResource (consumerRecord ) ? value .getType () : CREATE ;
183- return value .id (instanceId ).type (operation );
184- }
185-
186- private static String getInstanceId (ConsumerRecord <String , ResourceEvent > event ) {
187- var body = event .value ();
188- if (body .getType () == REINDEX ) {
189- return event .key ();
190- }
191- var eventPayload = getEventPayload (body );
192- return isInstanceResource (event ) ? getString (eventPayload , ID_FIELD ) : getString (eventPayload , INSTANCE_ID_FIELD );
193- }
194-
195- private static boolean isInstanceResource (ConsumerRecord <String , ResourceEvent > consumerRecord ) {
196- return consumerRecord .topic ().endsWith ("inventory.instance" );
197- }
198-
199185 private static void logFailedEvent (ResourceEvent event , Exception e ) {
200186 if (event == null ) {
201187 log .warn ("Failed to index resource event [event: null]" , e );
@@ -210,4 +196,15 @@ private static void logFailedEvent(ResourceEvent event, Exception e) {
210196 ), e );
211197 }
212198
199+ private static void logFailedEvent (IndexInstanceEvent event , Exception e ) {
200+ if (event == null ) {
201+ log .warn ("Failed to index resource event [event: null]" , e );
202+ return ;
203+ }
204+
205+ log .warn (new FormattedMessage (
206+ "Failed to index instance event [tenantId: {}, id: {}]" ,
207+ event .tenant (), event .instanceId ()
208+ ), e );
209+ }
213210}
0 commit comments