Skip to content

Commit

Permalink
Merge pull request #726 from iExecBlockchainComputing/release/8.6.0
Browse files Browse the repository at this point in the history
Release/8.6.0
  • Loading branch information
jbern0rd authored Dec 23, 2024
2 parents a3234eb + 18d2b2d commit 878dba8
Show file tree
Hide file tree
Showing 43 changed files with 791 additions and 474 deletions.
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@

All notable changes to this project will be documented in this file.

## [[8.6.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.6.0) 2024-12-23

### New Features

- Push scheduler Result Proxy URL as Web2 secret to SMS. (#718)

### Bug Fixes

- Start scheduler in out-of-service mode. (#712)
- Scheduler needs to enter out-of-service mode on first blockchain communication loss.
This is due to **Nethermind v1.14.7+99775bf7** where filters are lost on restart. (#715)
- Use Result Proxy URL defined in deal parameters if any, fall back to scheduler default one otherwise. (#716)
- Update off-chain task model with on-chain task consensus data in all workflows. (#720)

### Quality

- Reorder static and final keywords. (#717)
- Update `contribution` and `contributionAndFinalize` detector tests.
TEE tasks with callback are now eligible to `contributeAndFinalize` flow. (#719)
- Resolve deprecations caused by `TaskDescription` in `ReplicatesService` and `ResultService`. (#723)
- Add missing `@PreDestroy` annotation in services implementing `Purgeable`. (#724)

### Dependency Upgrades

- Upgrade to `eclipse-temurin:11.0.24_8-jre-focal`. (#713)
- Upgrade to Gradle 8.10.2. (#714)
- Upgrade to `testcontainers` 1.20.4. (#721)
- Upgrade to `mongo:7.0.15-jammy`. (#722)
- Upgrade to `iexec-commons-poco` 4.2.0. (#725)
- Upgrade to `iexec-common` 8.6.0. (#725)
- Upgrade to `iexec-blockchain-adapter-api-library` 8.6.0. (#725)
- Upgrade to `iexec-result-proxy-library` 8.6.0. (#725)
- Upgrade to `iexec-sms-library` 8.7.0. (#725)

## [[8.5.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.5.0) 2024-06-19

### Deprecation Notices
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM eclipse-temurin:11.0.22_7-jre-focal
FROM eclipse-temurin:11.0.24_8-jre-focal

ARG jar

Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ You can configure the _iExec Core Scheduler_ with the following properties:
| `IEXEC_CONFIG_SERVER_PROTOCOL` | _iExec Config Server_ communication protocol. | String | `http` |
| `IEXEC_CONFIG_SERVER_HOST` | _iExec Config Server_ host. | String | `localhost` |
| `IEXEC_CONFIG_SERVER_PORT` | _iExec Config Server_ port. | Positive integer | `8888` |
| `IEXEC_CHAIN_HEALTH_POLLING_INTERVAL_IN_BLOCKS` | Polling interval (in blocks) on the blockchain to check this _Scheduler_ can communicate with it. | Positive integer | 3 |
| `IEXEC_CHAIN_HEALTH_OUT_OF_SERVICE_THRESHOLD` | Max number of consecutive failures of blockchain connection attempts before this _Scheduler_ is declared as OUT-OF-SERVICE. | Positive integer | 4 |
| `IEXEC_RESULT_REPOSITORY_PROTOCOL` | _iExec Result Proxy_ server communication protocol. | String | `http` |
| `IEXEC_RESULT_REPOSITORY_HOST` | _iExec Result Proxy_ server host. | String | `localhost` |
| `IEXEC_RESULT_REPOSITORY_PORT` | _iExec Result Proxy_ server port. | Positive integer | `13200` |
Expand Down
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
plugins {
id 'java'
id 'io.freefair.lombok' version '8.6'
id 'io.freefair.lombok' version '8.10.2'
id 'org.springframework.boot' version '2.7.18'
id 'io.spring.dependency-management' version '1.1.4'
id 'io.spring.dependency-management' version '1.1.6'
id 'jacoco'
id 'org.sonarqube' version '5.0.0.4638'
id 'org.sonarqube' version '5.1.0.4882'
id 'maven-publish'
}

ext {
springCloudVersion = '2021.0.8'
jjwtVersion = '0.11.5'
mongockVersion = '4.2.7.BETA'
testContainersVersion = '1.19.0'
testContainersVersion = '1.20.4'
}

if (!project.hasProperty('gitBranch')) {
Expand Down Expand Up @@ -133,7 +133,7 @@ testing {

tasks.withType(Test).configureEach {
finalizedBy jacocoTestReport
systemProperty "mongo.image", "mongo:4.4.28-focal"
systemProperty "mongo.image", "mongo:7.0.15-jammy"
}

tasks.register('itest') {
Expand Down
12 changes: 6 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version=8.5.0
iexecCommonVersion=8.5.0
iexecCommonsPocoVersion=4.1.0
iexecBlockchainAdapterVersion=8.5.0
iexecResultVersion=8.5.0
iexecSmsVersion=8.6.0
version=8.6.0
iexecCommonsPocoVersion=4.2.0
iexecCommonVersion=8.6.0
iexecBlockchainAdapterVersion=8.6.0
iexecResultVersion=8.6.0
iexecSmsVersion=8.7.0
nexusUser
nexusPassword
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
7 changes: 5 additions & 2 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

##############################################################################
#
Expand Down Expand Up @@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Expand Down Expand Up @@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Expand Down
2 changes: 2 additions & 0 deletions gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2023 IEXEC BLOCKCHAIN TECH
* Copyright 2023-2024 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,14 +21,14 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.Clock;
import java.time.Duration;
import java.time.LocalDateTime;
Expand All @@ -49,18 +49,14 @@ public class BlockchainConnectionHealthIndicator implements HealthIndicator {
/**
* Number of consecutive failures before declaring this Scheduler is out-of-service.
*/
private final int outOfServiceThreshold;
private final ScheduledExecutorService monitoringExecutor;

/**
* Current number of consecutive failures.
* Current number of consecutive failures. Startup value is greater than {@literal 0} to be out-of-service.
*/
@Getter
private int consecutiveFailures = 0;
private int consecutiveFailures = 1;
@Getter
private LocalDateTime firstFailure = null;
@Getter
private boolean outOfService = false;

/**
* Required for test purposes.
Expand All @@ -71,15 +67,11 @@ public class BlockchainConnectionHealthIndicator implements HealthIndicator {
public BlockchainConnectionHealthIndicator(
ApplicationEventPublisher applicationEventPublisher,
Web3jService web3jService,
ChainConfig chainConfig,
@Value("${chain.health.pollingIntervalInBlocks}") int pollingIntervalInBlocks,
@Value("${chain.health.outOfServiceThreshold}") int outOfServiceThreshold) {
ChainConfig chainConfig) {
this(
applicationEventPublisher,
web3jService,
chainConfig,
pollingIntervalInBlocks,
outOfServiceThreshold,
Executors.newSingleThreadScheduledExecutor(),
Clock.systemDefaultZone()
);
Expand All @@ -89,28 +81,24 @@ public BlockchainConnectionHealthIndicator(
ApplicationEventPublisher applicationEventPublisher,
Web3jService web3jService,
ChainConfig chainConfig,
int pollingIntervalInBlocks,
int outOfServiceThreshold,
ScheduledExecutorService monitoringExecutor,
Clock clock) {
this.applicationEventPublisher = applicationEventPublisher;
this.web3jService = web3jService;
this.pollingInterval = chainConfig.getBlockTime().multipliedBy(pollingIntervalInBlocks);
this.outOfServiceThreshold = outOfServiceThreshold;
this.pollingInterval = chainConfig.getBlockTime();
this.monitoringExecutor = monitoringExecutor;
this.clock = clock;
}

@PostConstruct
@EventListener(ApplicationReadyEvent.class)
void scheduleMonitoring() {
monitoringExecutor.scheduleAtFixedRate(this::checkConnection, 0, pollingInterval.toSeconds(), TimeUnit.SECONDS);
}

/**
* Check blockchain is reachable by retrieving the latest block number.
* <p>
* If it isn't, then increment {@link BlockchainConnectionHealthIndicator#consecutiveFailures} counter.
* If counter reaches {@link BlockchainConnectionHealthIndicator#outOfServiceThreshold},
* If it isn't, then increment {@link BlockchainConnectionHealthIndicator#consecutiveFailures} counter,
* then this Health Indicator becomes {@link Status#OUT_OF_SERVICE}.
* <p>
* If blockchain is reachable, then reset the counter.
Expand All @@ -131,32 +119,20 @@ void checkConnection() {
/**
* Increment the {@link BlockchainConnectionHealthIndicator#consecutiveFailures} counter.
* <p>
* If first failure, set the {@link BlockchainConnectionHealthIndicator#firstFailure} to current time.
* <p>
* If {@link BlockchainConnectionHealthIndicator#outOfServiceThreshold} has been reached for the first time:
* If first failure:
* <ul>
* <li> Set {@link BlockchainConnectionHealthIndicator#outOfService} to {@literal true}
* <li> Publish a {@link ChainDisconnectedEvent} event.
* <li> Publish a {@link ChainDisconnectedEvent} event
* <li> Set the {@link BlockchainConnectionHealthIndicator#firstFailure} to current time
* </ul>
*/
private void connectionFailed() {
++consecutiveFailures;
if (consecutiveFailures >= outOfServiceThreshold) {
log.error("Blockchain hasn't been accessed for a long period. " +
"This Scheduler is now OUT-OF-SERVICE until communication is restored." +
" [unavailabilityPeriod:{}]", pollingInterval.multipliedBy(outOfServiceThreshold));
if (!outOfService) {
outOfService = true;
applicationEventPublisher.publishEvent(new ChainDisconnectedEvent(this));
}
} else {
if (consecutiveFailures == 1) {
firstFailure = LocalDateTime.now(clock);
}
log.warn("Blockchain is unavailable. Will retry connection." +
" [unavailabilityPeriod:{}, nextRetry:{}]",
pollingInterval.multipliedBy(consecutiveFailures), pollingInterval);
if (!isOutOfService()) {
log.error("Blockchain communication failed, this Scheduler is now OUT-OF-SERVICE until communication is restored.");
log.debug("Publishing ChainDisconnectedEvent");
applicationEventPublisher.publishEvent(new ChainDisconnectedEvent(this));
firstFailure = LocalDateTime.now(clock);
}
++consecutiveFailures;
}

/**
Expand All @@ -166,27 +142,24 @@ private void connectionFailed() {
* <ul>
* <li>Log a "connection restored" message.
* <li>Reset the {@link BlockchainConnectionHealthIndicator#firstFailure} var to {@code null}
* <li>If {@link Status#OUT_OF_SERVICE}, publish a {@link ChainConnectedEvent} event and reset the
* {@link BlockchainConnectionHealthIndicator#outOfService} state
* <li>If {@link Status#OUT_OF_SERVICE}, publish a {@link ChainConnectedEvent} event
* </ul>
*/
private void connectionSucceeded(long latestBlockNumber) {
if (consecutiveFailures > 0) {
if (isOutOfService()) {
log.info("Blockchain connection is now restored after a period of unavailability." +
" [block:{}, unavailabilityPeriod:{}]",
" [block:{}, unavailabilityPeriod:{}]",
latestBlockNumber, pollingInterval.multipliedBy(consecutiveFailures));
firstFailure = null;
consecutiveFailures = 0;
if (outOfService) {
outOfService = false;
applicationEventPublisher.publishEvent(new ChainConnectedEvent(this));
}
log.debug("Publishing ChainConnectedEvent");
applicationEventPublisher.publishEvent(new ChainConnectedEvent(this));
}
}

@Override
public Health health() {
final Health.Builder healthBuilder = outOfService
final Health.Builder healthBuilder = isOutOfService()
? Health.outOfService()
: Health.up();

Expand All @@ -197,10 +170,23 @@ public Health health() {
return healthBuilder
.withDetail("consecutiveFailures", consecutiveFailures)
.withDetail("pollingInterval", pollingInterval)
.withDetail("outOfServiceThreshold", outOfServiceThreshold)
.build();
}

/**
* Returns whether the scheduler should be considered out-of-service.
*
* @return {@literal true} in case of at least one consecutive failures, {@literal false} otherwise.
*/
public boolean isOutOfService() {
return consecutiveFailures > 0;
}

/**
* Returns whether the scheduler is up or not.
*
* @return {@literal true} if the scheduler is up, {@literal false} otherwise.
*/
public boolean isUp() {
return health().getStatus() == Status.UP;
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/iexec/core/chain/DealWatcherService.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import io.reactivex.disposables.Disposable;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
Expand Down Expand Up @@ -108,7 +107,7 @@ public DealWatcherService(ChainConfig chainConfig,
* a large number of tasks (BoT).
*/
@Async
@EventListener({ApplicationReadyEvent.class, ChainConnectedEvent.class})
@EventListener(ChainConnectedEvent.class)
public void run() {
outOfService = false;
disposeSubscription(dealEventsSubscription);
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/iexec/core/chain/IexecHubService.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.web3j.protocol.core.methods.request.EthFilter;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

import javax.annotation.PreDestroy;
import java.math.BigInteger;
import java.time.Instant;
import java.util.Date;
Expand Down Expand Up @@ -411,12 +412,15 @@ private EthFilter createEthFilter(long fromBlock, long toBlock, Event event) {
// endregion

@Override
public boolean purgeTask(String chainTaskId) {
public boolean purgeTask(final String chainTaskId) {
log.debug("purgeTask [chainTaskId: {}]", chainTaskId);
return super.purgeTask(chainTaskId);
}

@Override
@PreDestroy
public void purgeAllTasksData() {
log.info("Method purgeAllTasksData() called to perform task data cleanup.");
super.purgeAllTasksData();
}
}
Loading

0 comments on commit 878dba8

Please sign in to comment.