|
27 | 27 | import org.slf4j.LoggerFactory; |
28 | 28 | import org.sliceworkz.eventmodeling.aggregates.Aggregate; |
29 | 29 | import org.sliceworkz.eventmodeling.aggregates.AggregateCapability; |
| 30 | +import org.sliceworkz.eventmodeling.events.Instance; |
30 | 31 | import org.sliceworkz.eventstore.events.Tags; |
31 | 32 | import org.sliceworkz.eventstore.stream.EventStream; |
32 | 33 |
|
33 | | -// TODO add micrometer for observability |
| 34 | +import io.micrometer.core.instrument.Counter; |
| 35 | +import io.micrometer.core.instrument.MeterRegistry; |
| 36 | +import io.micrometer.core.instrument.Timer; |
| 37 | + |
34 | 38 | public class AggregateModule<DOMAIN_EVENT_TYPE> implements AggregateCapability<DOMAIN_EVENT_TYPE> { |
35 | 39 |
|
36 | 40 | private static final Logger LOGGER = LoggerFactory.getLogger(AggregateModule.class); |
37 | 41 |
|
38 | | - private Map<Class<? extends Aggregate<DOMAIN_EVENT_TYPE>>,Constructor<? extends Aggregate<DOMAIN_EVENT_TYPE>>> aggregateClassesWithConstructor = new HashMap<>(); |
| 42 | + private Map<Class<? extends Aggregate<DOMAIN_EVENT_TYPE>>,AggregateInfo<DOMAIN_EVENT_TYPE>> aggregateInfoByClass = new HashMap<>(); |
39 | 43 | private EventStream<DOMAIN_EVENT_TYPE> domainEventStream; |
40 | 44 | private String boundedContext; |
| 45 | + private Instance instance; |
| 46 | + private MeterRegistry meterRegistry; |
41 | 47 |
|
42 | | - public AggregateModule ( String boundedContext, List<? extends AggregateSpecificationImpl<DOMAIN_EVENT_TYPE,?,?>> aggregateSpecifications, EventStream<DOMAIN_EVENT_TYPE> domainEventStream ) { |
| 48 | + public AggregateModule ( String boundedContext, Instance instance, List<? extends AggregateSpecificationImpl<DOMAIN_EVENT_TYPE,?,?>> aggregateSpecifications, EventStream<DOMAIN_EVENT_TYPE> domainEventStream, MeterRegistry meterRegistry ) { |
43 | 49 | this.boundedContext = boundedContext; |
| 50 | + this.instance = instance; |
44 | 51 | this.domainEventStream = domainEventStream; |
| 52 | + this.meterRegistry = meterRegistry; |
| 53 | + |
| 54 | + io.micrometer.core.instrument.Tags tags = io.micrometer.core.instrument.Tags |
| 55 | + .of("context", boundedContext); |
| 56 | + |
45 | 57 | aggregateSpecifications.forEach(spec->{ |
46 | | - if ( aggregateClassesWithConstructor.containsKey(spec.aggregateClass()) ) { |
| 58 | + if ( aggregateInfoByClass.containsKey(spec.aggregateClass()) ) { |
47 | 59 | throw new IllegalArgumentException("duplicate aggregate registration for '%s'".formatted(spec.aggregateClass())); |
48 | 60 | } |
49 | 61 | try { |
50 | | - aggregateClassesWithConstructor.put(spec.aggregateClass(), spec.aggregateClass().getDeclaredConstructor(new Class[] {})); |
| 62 | + |
| 63 | + var aggregateTags = tags.and(io.micrometer.core.instrument.Tags.of("aggregate", spec.aggregateClass().getSimpleName())); |
| 64 | + |
| 65 | + Counter counter = meterRegistry.counter("sliceworkz.eventmodeling.aggregate.load.count", aggregateTags); |
| 66 | + Timer timer = meterRegistry.timer("sliceworkz.eventmodeling.aggregate.load.duration", aggregateTags); |
| 67 | + |
| 68 | + AggregateInfo<DOMAIN_EVENT_TYPE> aggregateInfo = new AggregateInfo<>(spec.aggregateClass().getDeclaredConstructor(new Class[] {}), counter, timer); |
| 69 | + |
| 70 | + aggregateInfoByClass.put(spec.aggregateClass(), aggregateInfo); |
51 | 71 | } catch (NoSuchMethodException | SecurityException e) { |
52 | 72 | LOGGER.error(e.getMessage(), e); |
53 | 73 | throw new RuntimeException(e); |
54 | 74 | } |
55 | 75 | }); |
56 | 76 |
|
57 | | - LOGGER.info("aggregates: %s".formatted(aggregateClassesWithConstructor.keySet())); |
| 77 | + LOGGER.info("aggregates: %s".formatted(aggregateInfoByClass.keySet())); |
58 | 78 | } |
59 | 79 |
|
60 | 80 | @SuppressWarnings("unchecked") |
61 | 81 | @Override |
62 | 82 | public <T extends Aggregate<DOMAIN_EVENT_TYPE>> T aggregate(Class<T> aggregateClass, Tags identity) { |
63 | 83 |
|
64 | | - if ( aggregateClassesWithConstructor.containsKey(aggregateClass)) { |
| 84 | + if ( aggregateInfoByClass.containsKey(aggregateClass)) { |
65 | 85 |
|
66 | 86 | if ( identity == null || identity.tags().size() < 1 ) { |
67 | 87 | throw new IllegalArgumentException("aggregate identity needs at least one tag, got '%s'".formatted(identity)); |
68 | 88 | } |
69 | 89 |
|
70 | | - T result; |
71 | | - try { |
72 | | - result = (T) aggregateClassesWithConstructor.get(aggregateClass).newInstance(new Object[] {}); |
73 | | - |
74 | | - AggregateContextImpl<DOMAIN_EVENT_TYPE> aci = new AggregateContextImpl<DOMAIN_EVENT_TYPE> (identity, result, domainEventStream); |
75 | | - result.setContext(aci); |
76 | | - aci.updateFromStream(); |
77 | | - |
78 | | - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
79 | | - | InvocationTargetException | SecurityException e) { |
80 | | - LOGGER.error(e.getMessage(), e); |
81 | | - throw new RuntimeException(e); |
82 | | - } |
83 | | - return result; |
| 90 | + AggregateInfo<DOMAIN_EVENT_TYPE> aggregateInfo = aggregateInfoByClass.get(aggregateClass); |
| 91 | + |
| 92 | + aggregateInfo.counter().increment(); |
| 93 | + |
| 94 | + return aggregateInfo.timer().record(()->{ |
| 95 | + T result; |
| 96 | + try { |
| 97 | + result = (T) aggregateInfo.constructor().newInstance(new Object[] {}); |
| 98 | + |
| 99 | + AggregateContextImpl<DOMAIN_EVENT_TYPE> aci = new AggregateContextImpl<DOMAIN_EVENT_TYPE> (boundedContext, instance, identity, result, domainEventStream); |
| 100 | + result.setContext(aci); |
| 101 | + aci.updateFromStream(); |
| 102 | + |
| 103 | + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
| 104 | + | InvocationTargetException | SecurityException e) { |
| 105 | + LOGGER.error(e.getMessage(), e); |
| 106 | + throw new RuntimeException(e); |
| 107 | + } |
| 108 | + return result; |
| 109 | + }); |
| 110 | + |
84 | 111 | } else { |
85 | 112 | throw new IllegalArgumentException("aggregate class '%s' not registered in bounded context '%s'".formatted(aggregateClass, boundedContext)); |
86 | 113 | } |
87 | 114 | } |
88 | 115 |
|
| 116 | + public record AggregateInfo<DOMAIN_EVENT_TYPE> ( |
| 117 | + Constructor<? extends Aggregate<DOMAIN_EVENT_TYPE>> constructor, |
| 118 | + Counter counter, |
| 119 | + Timer timer |
| 120 | + ) { } |
| 121 | + |
89 | 122 | } |
0 commit comments