[DISCUSSION] Workload splitting through Hazelcast
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- java, spring, spring-boot
- Domain
- backend, distributed-systems
Research direction
Start by reviewing the proposed HazelcastPartitionFilter and the adaptations to CloudDiscoveryService, the triggers, InstanceRegistry, and InstanceDiscoveryListener in the issue. Check how these components currently handle discovery and events, then assess whether the proposal covers all relevant code paths and preserves expected behavior across nodes. Done means reaching agreement on an approach before any large implementation PR.
Written by the indexing model from the issue text.
Description
Hello guys.
Recently I've been thinking to ways to make the current (half) clustering work fully so that jobs (e.g. StatusUpdateTrigger, InfoUpdateTrigger, NotificationTrigger and so on) are executed only on one one node while the whole state is anyway kept in sync with Hazelcast-specific collections.
I've therefore been working a bit with AI on this and this was a suggestion I got from it which, when I see it, code quality aside, it kind of makes sense to me:
@Component
public static class HazelcastPartitionFilter {
private final HazelcastInstance hazelcastInstance;
public HazelcastPartitionFilter(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
public boolean isMyPartition(InstanceId instanceId) {
if (instanceId == null || instanceId.getValue() == null) {
return false;
}
var partitionService = hazelcastInstance.getPartitionService();
Partition partition = partitionService.getPartition(instanceId.getValue());
return partition.getOwner() != null && partition.getOwner().localMember();
}
}
public static class HazelcastShardedDiscoveryService extends CloudDiscoveryService {
private final DiscoveryClient discoveryClient;
private final HazelcastPartitionFilter partitionFilter;
public HazelcastShardedDiscoveryService(DiscoveryClient discoveryClient,
HazelcastPartitionFilter partitionFilter) {
super(discoveryClient);
this.discoveryClient = discoveryClient;
this.partitionFilter = partitionFilter;
}
@Override
public Flux<Registration> convertToRegistrations(String serviceId) {
return Flux.fromIterable(discoveryClient.getInstances(serviceId))
.map(instance -> this.convertToRegistration(serviceId, instance))
.filter(reg -> partitionFilter.isMyPartition(reg.getInstanceId()));
}
}
@Bean
@Primary
public CloudDiscoveryService cloudDiscoveryService(DiscoveryClient discoveryClient,
HazelcastPartitionFilter partitionFilter) {
return new HazelcastShardedDiscoveryService(discoveryClient, partitionFilter);
}
@Bean
@Primary
public StatusUpdateTrigger statusUpdateTrigger(StatusUpdater statusUpdater, HazelcastPartitionFilter partitionFilter) {
return new StatusUpdateTrigger(statusUpdater) {
@Override
protected Publisher<Void> handle(InstanceEvent event) {
if (partitionFilter.isMyPartition(event.getInstance())) {
return super.handle(event);
}
return Mono.empty();
}
};
}
@Bean
@Primary
public InfoUpdateTrigger infoUpdateTrigger(InfoUpdater infoUpdater, HazelcastPartitionFilter partitionFilter) {
return new InfoUpdateTrigger(infoUpdater) {
@Override
protected Publisher<Void> handle(InstanceEvent event) {
if (partitionFilter.isMyPartition(event.getInstance())) {
return super.handle(event);
}
return Mono.empty();
}
};
}
@Bean
@Primary
public EndpointDetectionTrigger endpointDetectionTrigger(EndpointDetector endpointDetector, HazelcastPartitionFilter partitionFilter) {
return new EndpointDetectionTrigger(endpointDetector) {
@Override
protected Publisher<Void> handle(InstanceEvent event) {
if (partitionFilter.isMyPartition(event.getInstance())) {
return super.handle(event);
}
return Mono.empty();
}
};
}
@Bean
@Primary
public NotificationTrigger notificationTrigger(Notifier notifier,
InstanceRepository repository,
HazelcastPartitionFilter partitionFilter) {
return new NotificationTrigger(notifier, repository) {
@Override
protected Publisher<Void> handle(InstanceEvent event) {
if (partitionFilter.isMyPartition(event.getInstance())) {
return super.handle(event);
}
return Mono.empty();
}
};
}
@Bean
@Primary
public InstanceRegistry instanceRegistry(InstanceRepository repository,
InstanceIdGenerator idGenerator,
HazelcastPartitionFilter partitionFilter) {
return new InstanceRegistry(repository, idGenerator) {
@Override
public Mono<InstanceId> register(Registration registration) {
if (partitionFilter.isMyPartition(idGenerator.generateId(registration))) {
return super.register(registration);
}
return Mono.empty();
}
};
}
@Bean
@Primary
public InstanceDiscoveryListener instanceDiscoveryListener(CloudDiscoveryService discoveryService,
InstanceRegistry registry,
InstanceRepository repository) {
return new InstanceDiscoveryListener(discoveryService, registry, repository) {
@Override
public void discover() {
// Force the sync
super.discover();
}
};
}
I wanted to open this ticket to discuss with you the solution above and, in particular:
- if there any other code paths which I'm not aware of and that would require a similar adaptation
- if you think the solution above makes sense and it could actually work
- if you're willing to accept a PR with a polished version of the above (I can already anticipate it will be big)
- Dominant language
- Java
- Stars
- 12.9k
- Forks
- 3.2k
- Avg merge
- 13h 45m
- Merged PRs (30d)
- 95
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from codecentric/spring-boot-admin
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
codecentric/spring-boot-admin#5778 ·
Maintainers usually reply within 1 day
-
theme: server-ui type: enhancement
Difficulty 3/5 1-2 days Newbie friendliness 30/100
codecentric/spring-boot-admin#5765 ·
Maintainers usually reply within 1 day
-
Bug: Dependency Trees overflows the call stack on cyclic SBOM dependency graphsPossibly taken @faystmax claimed this 10 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 68/100
codecentric/spring-boot-admin#5746 ·
Maintainers usually reply within 1 day
-
Bug: Filtering rules are not synchronized between SBA nodesPossibly taken @SteKoe claimed this 12 days ago. Open
Difficulty 3/5 1-2 days Newbie friendliness 45/100
codecentric/spring-boot-admin#5721 · 3 comments ·
Maintainers usually reply within 1 day
-
Bug: Multiple notifications from multiple instancesPossibly taken @YadavKshitiz claimed this 14 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 55/100
codecentric/spring-boot-admin#5716 · 1 comment ·
Maintainers usually reply within 1 day
All issues in codecentric/spring-boot-admin
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
Flight SQL JDBC parses boolean properties case-sensitively, silently disabling TLS for useEncryption=TRUEPossibly taken @Arawoof06 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
apache/arrow-java#1357 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
apache/rocketmq-dashboard#6610 ·
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
MetricsHub/metricshub-community#1396 ·
Maintainers usually reply within 1 day
-
L: java:gradle L: java:maven L: ruby:bundler T: bug 🐞
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
dependabot/dependabot-core#16547 ·
Maintainers usually reply within 1 day