Skip to content

Commit 3ea873d

Browse files
authored
Improve configuration collection update at startup and when no deals has been detected for the last hour (#750)
1 parent e539ba9 commit 3ea873d

File tree

8 files changed

+224
-119
lines changed

8 files changed

+224
-119
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file.
77
### New Features
88

99
- Add WebSocketBlockchainListener to fetch latest block without polling the blockchain network. (#747)
10+
- Update last seen block in configuration collection when no deal has been detected in the last hour. (#750)
11+
- Update configuration collection depending on chain.start-block-number at startup. (#750)
1012

1113
### Bug Fixes
1214

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ You can configure the _iExec Core Scheduler_ with the following properties:
4949
| `IEXEC_LOGS_AVAILABILITY_PERIOD_IN_DAYS` | Number of days to keep logs of past tasks. | Positive integer | `3` |
5050

5151
If it is not the first startup of the _iExec Core Scheduler_ and if it received deals previously,
52-
the _MongoDB_ instance will contain a __configuration Collection__ in the __iexec Database__.
53-
The value stored in this document takes the precedence over the `IEXEC_START_BLOCK_NUMBER` configuration parameter.
54-
To enforce deal observation starting from the `IEXEC_START_BLOCK_NUMBER` value, the aforementioned document has to be deleted in the _MongoDB_.
55-
All deals prior to the `IEXEC_START_BLOCK_NUMBER` will then be ignored.
52+
the _MongoDB_ instance will contain both __configuration__ and __replayConfiguration__ collections in the __iexec Database__.
53+
The highest value between the value stored in this document and the `IEXEC_START_BLOCK_NUMBER` configuration parameter takes precedence.
54+
If the stored value takes precedence, the `IEXEC_START_BLOCK_NUMBER` is ignored.
55+
Otherwise, the __configuration__ and __replayConfiguration__ collections will be updated with `IEXEC_START_BLOCK_NUMBER` during startup.
56+
All deals between the previous configured value and the `IEXEC_START_BLOCK_NUMBER` will then be ignored.
5657

5758
A more exhaustive documentation is available on [the official documentation of iExec](https://docs.iex.ec/).
5859

src/main/java/com/iexec/core/chain/DealWatcherService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class DealWatcherService {
6565
private final TaskService taskService;
6666
private final Web3jService web3jService;
6767
// internal variables
68-
private boolean outOfService;
68+
private boolean outOfService = true;
6969
private Disposable dealEventsSubscription;
7070
private Disposable dealEventSubscriptionReplay;
7171
@Getter
@@ -254,16 +254,16 @@ boolean shouldProcessDeal(ChainDeal chainDeal) {
254254
*/
255255
@Scheduled(fixedRateString = "#{@cronConfiguration.getDealReplay()}")
256256
void replayDealEvent() {
257-
BigInteger lastSeenBlockWithDeal = configurationService.getLastSeenBlockWithDeal();
258-
BigInteger replayFromBlock = configurationService.getFromReplay();
259-
if (replayFromBlock.compareTo(lastSeenBlockWithDeal) >= 0) {
260-
return;
261-
}
262257
disposeSubscription(dealEventSubscriptionReplay);
263258
if (outOfService) {
264259
log.info("OUT-OF-SERVICE do not create replay subscription");
265260
return;
266261
}
262+
final BigInteger lastSeenBlockWithDeal = configurationService.getLastSeenBlockWithDeal();
263+
final BigInteger replayFromBlock = configurationService.getFromReplay();
264+
if (replayFromBlock.compareTo(lastSeenBlockWithDeal) >= 0) {
265+
return;
266+
}
267267
dealEventSubscriptionReplay = subscribeToDealEventInRange(replayFromBlock, lastSeenBlockWithDeal);
268268
configurationService.setFromReplay(lastSeenBlockWithDeal);
269269
}

src/main/java/com/iexec/core/configuration/Configuration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.springframework.data.annotation.Version;
2525

2626
import java.math.BigInteger;
27+
import java.time.Instant;
2728

2829
@Data
2930
@AllArgsConstructor
@@ -38,6 +39,7 @@ class Configuration {
3839
private Long version;
3940

4041
private BigInteger lastSeenBlockWithDeal;
42+
private Instant lastUpdate;
4143

4244
}
4345

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,17 +17,27 @@
1717
package com.iexec.core.configuration;
1818

1919
import com.iexec.core.chain.ChainConfig;
20+
import com.iexec.core.chain.event.LatestBlockEvent;
21+
import lombok.extern.slf4j.Slf4j;
22+
import org.springframework.boot.CommandLineRunner;
23+
import org.springframework.context.event.EventListener;
2024
import org.springframework.stereotype.Service;
2125

2226
import java.math.BigInteger;
27+
import java.time.Instant;
28+
import java.time.temporal.ChronoUnit;
2329

30+
@Slf4j
2431
@Service
25-
public class ConfigurationService {
32+
public class ConfigurationService implements CommandLineRunner {
2633

2734
private final ConfigurationRepository configurationRepository;
2835
private final ReplayConfigurationRepository replayConfigurationRepository;
2936
private final ChainConfig chainConfig;
3037

38+
private Configuration configuration;
39+
private ReplayConfiguration replayConfiguration;
40+
3141
public ConfigurationService(ConfigurationRepository configurationRepository,
3242
ReplayConfigurationRepository replayConfigurationRepository,
3343
ChainConfig chainConfig) {
@@ -36,46 +46,84 @@ public ConfigurationService(ConfigurationRepository configurationRepository,
3646
this.chainConfig = chainConfig;
3747
}
3848

39-
private Configuration getConfiguration() {
40-
if (configurationRepository.count() > 0)
41-
return configurationRepository.findAll().get(0);
42-
43-
return configurationRepository.save(
44-
Configuration
45-
.builder()
46-
.lastSeenBlockWithDeal(BigInteger.valueOf(chainConfig.getStartBlockNumber()))
47-
.build());
49+
/**
50+
* Update last scanned block in configuration.
51+
*
52+
* @param event Event containing last block number
53+
*/
54+
@EventListener
55+
void setLastScannedBlock(final LatestBlockEvent event) {
56+
final Instant now = Instant.now();
57+
if (now.isAfter(configuration.getLastUpdate().plus(1L, ChronoUnit.HOURS))) {
58+
updateConfiguration(BigInteger.valueOf(event.getBlockNumber()));
59+
}
4860
}
4961

5062
public BigInteger getLastSeenBlockWithDeal() {
51-
return this.getConfiguration().getLastSeenBlockWithDeal();
63+
return configuration.getLastSeenBlockWithDeal();
5264
}
5365

54-
public void setLastSeenBlockWithDeal(BigInteger lastBlockNumber) {
55-
Configuration configuration = this.getConfiguration();
56-
configuration.setLastSeenBlockWithDeal(lastBlockNumber);
57-
configurationRepository.save(configuration);
66+
public void setLastSeenBlockWithDeal(final BigInteger lastBlockNumber) {
67+
updateConfiguration(lastBlockNumber);
5868
}
5969

60-
private ReplayConfiguration getReplayConfiguration() {
61-
if (replayConfigurationRepository.count() > 0)
62-
return replayConfigurationRepository.findAll().get(0);
63-
64-
return replayConfigurationRepository.save(
65-
ReplayConfiguration
66-
.builder()
67-
.fromBlockNumber(BigInteger.valueOf(chainConfig.getStartBlockNumber()))
68-
.build());
70+
private synchronized void updateConfiguration(final BigInteger lastBlockNumber) {
71+
configuration.setLastSeenBlockWithDeal(lastBlockNumber);
72+
configuration.setLastUpdate(Instant.now());
73+
configuration = configurationRepository.save(configuration);
6974
}
7075

7176
public BigInteger getFromReplay() {
72-
return this.getReplayConfiguration().getFromBlockNumber();
77+
return replayConfiguration.getFromBlockNumber();
7378
}
7479

7580
public void setFromReplay(BigInteger fromReplay) {
76-
ReplayConfiguration replayConfiguration = this.getReplayConfiguration();
7781
replayConfiguration.setFromBlockNumber(fromReplay);
78-
replayConfigurationRepository.save(replayConfiguration);
82+
replayConfiguration = replayConfigurationRepository.save(replayConfiguration);
83+
}
84+
85+
@Override
86+
public void run(String... args) throws Exception {
87+
final String messageDetails = String.format("[start:block:%s]", chainConfig.getStartBlockNumber());
88+
final Instant now = Instant.now();
89+
if (configurationRepository.count() == 0) {
90+
log.info("Creating configuration {}", messageDetails);
91+
configuration = configurationRepository.save(
92+
Configuration
93+
.builder()
94+
.lastSeenBlockWithDeal(BigInteger.valueOf(chainConfig.getStartBlockNumber()))
95+
.lastUpdate(now)
96+
.build());
97+
} else {
98+
configuration = configurationRepository.findAll().get(0);
99+
if (chainConfig.getStartBlockNumber() > configuration.getLastSeenBlockWithDeal().longValue()) {
100+
log.info("Updating configuration {}", messageDetails);
101+
configuration.setLastSeenBlockWithDeal(BigInteger.valueOf(chainConfig.getStartBlockNumber()));
102+
configuration.setLastUpdate(now);
103+
configuration = configurationRepository.save(configuration);
104+
} else {
105+
log.info("Keeping current configuration [start-block:{}]", configuration.getLastSeenBlockWithDeal());
106+
}
107+
}
108+
if (replayConfigurationRepository.count() == 0) {
109+
log.info("Creating replay configuration {}", messageDetails);
110+
replayConfiguration = replayConfigurationRepository.save(
111+
ReplayConfiguration
112+
.builder()
113+
.fromBlockNumber(BigInteger.valueOf(chainConfig.getStartBlockNumber()))
114+
.lastUpdate(now)
115+
.build());
116+
} else {
117+
replayConfiguration = replayConfigurationRepository.findAll().get(0);
118+
if (chainConfig.getStartBlockNumber() > replayConfiguration.getFromBlockNumber().longValue()) {
119+
log.info("Updating replay configuration {}", messageDetails);
120+
replayConfiguration.setFromBlockNumber(BigInteger.valueOf(chainConfig.getStartBlockNumber()));
121+
replayConfiguration.setLastUpdate(now);
122+
replayConfiguration = replayConfigurationRepository.save(replayConfiguration);
123+
} else {
124+
log.info("Keeping current replay configuration [start-block:{}]", replayConfiguration.getFromBlockNumber());
125+
}
126+
}
79127
}
80128

81129
}

src/main/java/com/iexec/core/configuration/ReplayConfiguration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.springframework.data.annotation.Version;
2525

2626
import java.math.BigInteger;
27+
import java.time.Instant;
2728

2829
@Data
2930
@AllArgsConstructor
@@ -38,6 +39,7 @@ class ReplayConfiguration {
3839
private Long version;
3940

4041
private BigInteger fromBlockNumber;
42+
private Instant lastUpdate;
4143

4244
}
4345

src/test/java/com/iexec/core/chain/DealWatcherServiceTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ void shouldReplayAllEventInRange() {
332332

333333
@Test
334334
void shouldNotReplayIfFromReplayEqualsLastSeenBlock() {
335+
ReflectionTestUtils.setField(dealWatcherService, OUT_OF_SERVICE_FIELD_NAME, false);
335336
when(configurationService.getLastSeenBlockWithDeal()).thenReturn(BigInteger.ZERO);
336337
when(configurationService.getFromReplay()).thenReturn(BigInteger.ZERO);
337338
dealWatcherService.replayDealEvent();
@@ -340,11 +341,8 @@ void shouldNotReplayIfFromReplayEqualsLastSeenBlock() {
340341

341342
@Test
342343
void shouldNotReplayIfOutOfService() {
343-
ReflectionTestUtils.setField(dealWatcherService, OUT_OF_SERVICE_FIELD_NAME, true);
344-
when(configurationService.getLastSeenBlockWithDeal()).thenReturn(BigInteger.TEN);
345-
when(configurationService.getFromReplay()).thenReturn(BigInteger.ZERO);
346344
dealWatcherService.replayDealEvent();
347-
verifyNoInteractions(iexecHubService);
345+
verifyNoInteractions(configurationService, iexecHubService);
348346
}
349347
// endregion
350348

0 commit comments

Comments
 (0)