Added new metric 'roompicker_locked_rooms'
This commit is contained in:
parent
cf76f2f8ce
commit
d185072ee0
@ -9,12 +9,17 @@ import lombok.extern.log4j.Log4j2;
|
||||
import org.aspectj.lang.annotation.After;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.dragonestia.picker.event.UpdateRoomLockStateEvent;
|
||||
import ru.dragonestia.picker.model.Node;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
import ru.dragonestia.picker.repository.UserRepository;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -28,64 +33,94 @@ public class UserMetricsAspect {
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
private final AtomicInteger totalUsers = new AtomicInteger(0);
|
||||
private final Map<String, Gauge> nodeGauges = new ConcurrentHashMap<>();
|
||||
private final Map<String, Integer> nodeUsers = new ConcurrentHashMap<>();
|
||||
private final Map<String, Counter> pickPerMinute = new ConcurrentHashMap<>();
|
||||
private final Map<String, NodeData> data = new ConcurrentHashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
meterRegistry.gauge("roompicker_total_users", totalUsers);
|
||||
}
|
||||
|
||||
@After("execution(* ru.dragonestia.picker.repository.UserRepository.linkWithRoom(..))")
|
||||
void onLinkUsers() {
|
||||
countAllUsers();
|
||||
@After(value = "execution(* ru.dragonestia.picker.repository.UserRepository.linkWithRoom(ru.dragonestia.picker.model.Room, ..)) && args(room, ..)", argNames = "room")
|
||||
void onLinkUsers(Room room) {
|
||||
countAllUsers(room);
|
||||
}
|
||||
|
||||
@After("execution(void ru.dragonestia.picker.repository.UserRepository.unlinkWithRoom(..))")
|
||||
void onUnlinkUsers() {
|
||||
countAllUsers();
|
||||
@After(value = "execution(void ru.dragonestia.picker.repository.UserRepository.unlinkWithRoom(ru.dragonestia.picker.model.Room, ..)) && args(room, ..)", argNames = "room")
|
||||
void onUnlinkUsers(Room room) {
|
||||
countAllUsers(room);
|
||||
}
|
||||
|
||||
@After("execution(void ru.dragonestia.picker.repository.UserRepository.onRemoveRoom(..))")
|
||||
void onRemoveRoom() {
|
||||
countAllUsers();
|
||||
@AfterReturning(value = "execution(void ru.dragonestia.picker.repository.RoomRepository.create(ru.dragonestia.picker.model.Room)) && args(room)", argNames = "room")
|
||||
void onCreateRoom(Room room) {
|
||||
checkRoom(room);
|
||||
}
|
||||
|
||||
private void countAllUsers() {
|
||||
@After(value = "execution(void ru.dragonestia.picker.repository.UserRepository.onRemoveRoom(ru.dragonestia.picker.model.Room)) && args(room, ..)", argNames = "room")
|
||||
void onRemoveRoom(Room room) {
|
||||
countAllUsers(room);
|
||||
}
|
||||
|
||||
private void countAllUsers(Room room) {
|
||||
totalUsers.set(userRepository.countAllUsers());
|
||||
|
||||
checkRoom(room);
|
||||
}
|
||||
|
||||
private void checkRoom(Room room) {
|
||||
var set = data.get(room.getNodeIdentifier()).locked();
|
||||
if (room.isLocked()) {
|
||||
set.add(room);
|
||||
return;
|
||||
}
|
||||
if (!room.hasUnlimitedSlots() && userRepository.usersOf(room).size() >= room.getMaxSlots()) {
|
||||
set.add(room);
|
||||
return;
|
||||
}
|
||||
set.remove(room);
|
||||
}
|
||||
|
||||
@After(value = "execution(void ru.dragonestia.picker.repository.NodeRepository.create(ru.dragonestia.picker.model.Node)) && args(node)", argNames = "node")
|
||||
void onCreateNode(Node node) {
|
||||
var nodeId = node.getIdentifier();
|
||||
var gauge = Gauge.builder("roompicker_node_users_total", () -> nodeUsers.getOrDefault(nodeId, 0))
|
||||
var gauge = Gauge.builder("roompicker_node_users_total", () -> data.get(nodeId).users())
|
||||
.tag("nodeId", nodeId)
|
||||
.register(meterRegistry);
|
||||
|
||||
nodeGauges.put(nodeId, gauge);
|
||||
|
||||
var counter = Counter.builder("roompicker_picks")
|
||||
.tag("nodeId", nodeId)
|
||||
.baseUnit("1s")
|
||||
.register(meterRegistry);
|
||||
pickPerMinute.put(nodeId, counter);
|
||||
|
||||
var lockedGauge = Gauge.builder("roompicker_locked_rooms", () -> data.get(nodeId).locked().size())
|
||||
.tag("nodeId", nodeId)
|
||||
.register(meterRegistry);
|
||||
|
||||
data.put(nodeId, new NodeData(gauge, new AtomicInteger(0), counter, new HashSet<>(), lockedGauge));
|
||||
}
|
||||
|
||||
@After(value = "execution(* ru.dragonestia.picker.repository.NodeRepository.delete(ru.dragonestia.picker.model.Node)) && args(node)", argNames = "node")
|
||||
void onDeleteNode(Node node) {
|
||||
meterRegistry.remove(nodeGauges.remove(node.getIdentifier()));
|
||||
meterRegistry.remove(pickPerMinute.remove(node.getIdentifier()));
|
||||
nodeUsers.remove(node.getIdentifier());
|
||||
var data = this.data.remove(node.getIdentifier());
|
||||
|
||||
meterRegistry.remove(data.usersGauge());
|
||||
meterRegistry.remove(data.picksPerMinute());
|
||||
meterRegistry.remove(data.lockedGauge());
|
||||
}
|
||||
|
||||
@AfterReturning(value = "execution(* ru.dragonestia.picker.repository.RoomRepository.pickFree(ru.dragonestia.picker.model.Node, *)) && args(node, ..)", argNames = "node")
|
||||
void onPickRoom(Node node) {
|
||||
pickPerMinute.get(node.getIdentifier()).increment();
|
||||
data.get(node.getIdentifier()).picksPerMinute().increment();
|
||||
}
|
||||
|
||||
@EventListener
|
||||
void onRoomChangeLockState(UpdateRoomLockStateEvent event) {
|
||||
checkRoom(event.room());
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 3_000)
|
||||
void updateUserMetrics() {
|
||||
nodeUsers.putAll(userRepository.countUsersForNodes());
|
||||
userRepository.countUsersForNodes().forEach((nodeId, users) -> data.get(nodeId).users().set(users));
|
||||
}
|
||||
|
||||
private record NodeData(Gauge usersGauge, AtomicInteger users, Counter picksPerMinute, Set<Room> locked, Gauge lockedGauge) {}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import ru.dragonestia.picker.interceptor.DebugInterceptor;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
import ru.dragonestia.picker.model.Node;
|
||||
import ru.dragonestia.picker.model.User;
|
||||
import ru.dragonestia.picker.model.factory.RoomFactory;
|
||||
import ru.dragonestia.picker.model.type.SlotLimit;
|
||||
import ru.dragonestia.picker.repository.RoomRepository;
|
||||
import ru.dragonestia.picker.repository.NodeRepository;
|
||||
@ -36,6 +37,7 @@ public class TestConfig implements WebMvcConfigurer {
|
||||
private final NodeRepository nodeRepository;
|
||||
private final RoomRepository roomRepository;
|
||||
private final UserRepository userRepository;
|
||||
private final RoomFactory roomFactory;
|
||||
|
||||
private final Random rand = new Random(0);
|
||||
|
||||
@ -58,7 +60,7 @@ public class TestConfig implements WebMvcConfigurer {
|
||||
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
var slots = 5 * i;
|
||||
var room = new Room(RoomIdentifier.of("test-" + i), node, slots, json.writeValueAsString(generatePayload()), false);
|
||||
var room = roomFactory.create(RoomIdentifier.of("test-" + i), node, slots, json.writeValueAsString(generatePayload()), false);
|
||||
roomRepository.create(room);
|
||||
|
||||
for (int j = 0, n = rand.nextInt(slots + 1); j < n; j++) {
|
||||
@ -68,7 +70,7 @@ public class TestConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
var room = new Room(RoomIdentifier.of(randomUUID().toString()), node, IRoom.UNLIMITED_SLOTS, json.writeValueAsString(generatePayload()), false);
|
||||
var room = roomFactory.create(RoomIdentifier.of(randomUUID().toString()), node, IRoom.UNLIMITED_SLOTS, json.writeValueAsString(generatePayload()), false);
|
||||
room.setLocked((i & 1) == 0);
|
||||
roomRepository.create(room);
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import ru.dragonestia.picker.api.repository.response.RoomInfoResponse;
|
||||
import ru.dragonestia.picker.api.repository.response.RoomListResponse;
|
||||
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
import ru.dragonestia.picker.model.factory.RoomFactory;
|
||||
import ru.dragonestia.picker.service.RoomService;
|
||||
import ru.dragonestia.picker.service.NodeService;
|
||||
import ru.dragonestia.picker.util.DetailsParser;
|
||||
@ -28,6 +29,7 @@ public class RoomController {
|
||||
private final RoomService roomService;
|
||||
private final NamingValidator namingValidator;
|
||||
private final DetailsParser detailsParser;
|
||||
private final RoomFactory roomFactory;
|
||||
|
||||
@Operation(summary = "Get all rooms from node")
|
||||
@GetMapping
|
||||
@ -54,7 +56,7 @@ public class RoomController {
|
||||
@Parameter(description = "Save room") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist
|
||||
) {
|
||||
var node = nodeService.find(nodeId).orElseThrow(() -> new NodeNotFoundException(nodeId));
|
||||
var room = new Room(RoomIdentifier.of(roomId), node, slots, payload, persist);
|
||||
var room = roomFactory.create(RoomIdentifier.of(roomId), node, slots, payload, persist);
|
||||
room.setLocked(locked);
|
||||
roomService.create(room);
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
package ru.dragonestia.picker.event;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public record UpdateRoomLockStateEvent(@NotNull Room room) {
|
||||
|
||||
public interface Listener extends Consumer<UpdateRoomLockStateEvent> {}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import ru.dragonestia.picker.api.model.room.ResponseRoom;
|
||||
import ru.dragonestia.picker.api.model.room.RoomDetails;
|
||||
import ru.dragonestia.picker.api.model.room.ShortResponseRoom;
|
||||
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;
|
||||
import ru.dragonestia.picker.event.UpdateRoomLockStateEvent;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -18,13 +19,15 @@ public class Room implements IRoom {
|
||||
private final String payload;
|
||||
private final boolean persist;
|
||||
private boolean locked = false;
|
||||
private final UpdateRoomLockStateEvent.Listener updateLockStateListener;
|
||||
|
||||
public Room(@NotNull RoomIdentifier identifier, @NotNull Node node, int slots, @NotNull String payload, boolean persist) {
|
||||
public Room(@NotNull RoomIdentifier identifier, @NotNull Node node, int slots, @NotNull String payload, boolean persist, @Nullable UpdateRoomLockStateEvent.Listener listener) {
|
||||
this.identifier = identifier.getValue();
|
||||
this.nodeIdentifier = node.getIdentifier();
|
||||
this.slots = slots;
|
||||
this.payload = payload;
|
||||
this.persist = persist;
|
||||
this.updateLockStateListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -49,6 +52,10 @@ public class Room implements IRoom {
|
||||
|
||||
public void setLocked(boolean value) {
|
||||
locked = value;
|
||||
|
||||
if (updateLockStateListener != null) {
|
||||
updateLockStateListener.accept(new UpdateRoomLockStateEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package ru.dragonestia.picker.model.factory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;
|
||||
import ru.dragonestia.picker.model.Node;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RoomFactory {
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Contract("_, _, _, _, _ -> new")
|
||||
public @NotNull Room create(@NotNull RoomIdentifier identifier, @NotNull Node node, int slots, @NotNull String payload, boolean persist) {
|
||||
return new Room(identifier, node, slots, payload, persist, eventPublisher::publishEvent);
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import ru.dragonestia.picker.api.repository.type.UserIdentifier;
|
||||
import ru.dragonestia.picker.model.Node;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
import ru.dragonestia.picker.model.User;
|
||||
import ru.dragonestia.picker.model.factory.RoomFactory;
|
||||
import ru.dragonestia.picker.repository.NodeRepository;
|
||||
import ru.dragonestia.picker.repository.RoomRepository;
|
||||
import ru.dragonestia.picker.repository.UserRepository;
|
||||
@ -47,6 +48,9 @@ public class FillingNodesConfig {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoomFactory roomFactory;
|
||||
|
||||
private Node seqNode;
|
||||
private Node roundNode;
|
||||
private Node leastNode;
|
||||
@ -85,7 +89,7 @@ public class FillingNodesConfig {
|
||||
for (int i = 0, n = 5; i < n; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
var roomId = "room-" + i + "-" + j;
|
||||
var room = new Room(RoomIdentifier.of(roomId), node, n, "", false);
|
||||
var room = roomFactory.create(RoomIdentifier.of(roomId), node, n, "", false);
|
||||
roomRepository.create(room);
|
||||
|
||||
var users = n - i;
|
||||
|
||||
@ -17,6 +17,7 @@ import ru.dragonestia.picker.api.repository.type.UserIdentifier;
|
||||
import ru.dragonestia.picker.model.Node;
|
||||
import ru.dragonestia.picker.model.Room;
|
||||
import ru.dragonestia.picker.model.User;
|
||||
import ru.dragonestia.picker.model.factory.RoomFactory;
|
||||
import ru.dragonestia.picker.model.type.SlotLimit;
|
||||
|
||||
import java.util.List;
|
||||
@ -30,6 +31,9 @@ public class RoomServiceTests {
|
||||
@Autowired
|
||||
private RoomService roomService;
|
||||
|
||||
@Autowired
|
||||
private RoomFactory roomFactory;
|
||||
|
||||
private Node node;
|
||||
|
||||
@BeforeEach
|
||||
@ -43,7 +47,7 @@ public class RoomServiceTests {
|
||||
|
||||
@Test
|
||||
void test_createAndRemove() {
|
||||
var room = new Room(RoomIdentifier.of("test-room"), node, IRoom.UNLIMITED_SLOTS, "", false);
|
||||
var room = roomFactory.create(RoomIdentifier.of("test-room"), node, IRoom.UNLIMITED_SLOTS, "", false);
|
||||
roomService.create(room);
|
||||
|
||||
Assertions.assertTrue(roomService.find(node, room.getIdentifier()).isPresent());
|
||||
@ -57,10 +61,10 @@ public class RoomServiceTests {
|
||||
@Test
|
||||
void test_allRooms() {
|
||||
var rooms = List.of(
|
||||
new Room(RoomIdentifier.of("test-room1"), node, 1, "", false),
|
||||
new Room(RoomIdentifier.of("test-room2"), node, 2, "", false),
|
||||
new Room(RoomIdentifier.of("test-room3"), node, 3, "", false),
|
||||
new Room(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false)
|
||||
roomFactory.create(RoomIdentifier.of("test-room1"), node, 1, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room2"), node, 2, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room3"), node, 3, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false)
|
||||
);
|
||||
|
||||
rooms.forEach(room -> roomService.create(room));
|
||||
@ -74,17 +78,17 @@ public class RoomServiceTests {
|
||||
@Test
|
||||
void test_exceptNotPersistedNode() {
|
||||
Assertions.assertThrows(NotPersistedNodeException.class, () -> {
|
||||
roomService.create(new Room(RoomIdentifier.of("1"), node, IRoom.UNLIMITED_SLOTS, "", true));
|
||||
roomService.create(roomFactory.create(RoomIdentifier.of("1"), node, IRoom.UNLIMITED_SLOTS, "", true));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_pickRoom() {
|
||||
var rooms = List.of(
|
||||
new Room(RoomIdentifier.of("test-room1"), node, 1, "", false),
|
||||
new Room(RoomIdentifier.of("test-room2"), node, 2, "", false),
|
||||
new Room(RoomIdentifier.of("test-room3"), node, 3, "", false),
|
||||
new Room(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false)
|
||||
roomFactory.create(RoomIdentifier.of("test-room1"), node, 1, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room2"), node, 2, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room3"), node, 3, "", false),
|
||||
roomFactory.create(RoomIdentifier.of("test-room4"), node, IRoom.UNLIMITED_SLOTS, "", false)
|
||||
);
|
||||
|
||||
rooms.forEach(room -> roomService.create(room));
|
||||
@ -112,7 +116,7 @@ public class RoomServiceTests {
|
||||
@Test
|
||||
void test_nodeDoesNotExists() {
|
||||
var node = new Node(NodeIdentifier.of("bruh"), PickingMethod.ROUND_ROBIN, false);
|
||||
var room = new Room(RoomIdentifier.of("test"), node, IRoom.UNLIMITED_SLOTS, "", false);
|
||||
var room = roomFactory.create(RoomIdentifier.of("test"), node, IRoom.UNLIMITED_SLOTS, "", false);
|
||||
|
||||
Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.create(room));
|
||||
Assertions.assertThrows(NodeNotFoundException.class, () -> roomService.remove(room));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user