You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampark.apache.org by be...@apache.org on 2023/01/11 11:07:23 UTC
[incubator-streampark] branch dev updated: [Improve] read flink on k8s deploy log improvement (#2243)
This is an automated email from the ASF dual-hosted git repository.
benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git
The following commit(s) were added to refs/heads/dev by this push:
new f8fe8406b [Improve] read flink on k8s deploy log improvement (#2243)
f8fe8406b is described below
commit f8fe8406bfc8c31942af4d3c6093c68d3e31ec77
Author: benjobs <be...@apache.org>
AuthorDate: Wed Jan 11 19:07:16 2023 +0800
[Improve] read flink on k8s deploy log improvement (#2243)
* [Improve] CompletableFuture improvement
* [Improve] read flink on k8s deploy log improvement
* [Improve] call CompletableFuture method change to CompletableFutureUtils
* [Improve] CompletableFutureUtils improvement
* [Improve] exception testcase improvement
---
.../common/util/CompletableFutureUtils.scala | 45 ++++----
.../streampark/console/base/util/MoreFutures.java | 125 ---------------------
.../core/controller/ApplicationController.java | 25 +----
.../console/core/service/ApplicationService.java | 2 +
.../console/core/service/LogClientService.java | 48 +++-----
.../console/core/service/LoggerService.java | 25 -----
.../core/service/impl/ApplicationServiceImpl.java | 42 ++++++-
.../core/service/impl/LoggerServiceImpl.java | 65 -----------
.../common/util/CompletableFutureUtilsTest.java} | 81 ++++++++++++-
.../src/api/flink/app/app.ts | 6 +-
.../flink/app/components/AppView/LogModal.vue | 20 ++--
11 files changed, 179 insertions(+), 305 deletions(-)
diff --git a/streampark-common/src/main/scala/org/apache/streampark/common/util/CompletableFutureUtils.scala b/streampark-common/src/main/scala/org/apache/streampark/common/util/CompletableFutureUtils.scala
index cc5bfdeb9..838c4f6c7 100644
--- a/streampark-common/src/main/scala/org/apache/streampark/common/util/CompletableFutureUtils.scala
+++ b/streampark-common/src/main/scala/org/apache/streampark/common/util/CompletableFutureUtils.scala
@@ -17,8 +17,8 @@
package org.apache.streampark.common.util
-import java.util.concurrent.{Callable, CompletableFuture, ScheduledThreadPoolExecutor, ThreadFactory, TimeoutException, TimeUnit}
-import java.util.function.{Consumer, Function => JavaFunc}
+import java.util.concurrent.{Callable, CompletableFuture, ScheduledThreadPoolExecutor, ThreadFactory, TimeUnit, TimeoutException}
+import java.util.function.{BiConsumer, Consumer, Function => JavaFunc}
object CompletableFutureUtils {
@@ -39,7 +39,7 @@ object CompletableFutureUtils {
delayer
}
- def setTimeout[T](timeout: Long, unit: TimeUnit): CompletableFuture[T] = {
+ private[this] def setTimeout[T](timeout: Long, unit: TimeUnit): CompletableFuture[T] = {
val result = new CompletableFuture[T]
completableDelayer.schedule(
new Callable[Boolean] {
@@ -56,7 +56,16 @@ object CompletableFutureUtils {
unit: TimeUnit,
handle: JavaFunc[T, T],
exceptionally: JavaFunc[Throwable, T]): CompletableFuture[T] = {
- future.applyToEither(setTimeout(timeout, unit), handle).exceptionally(exceptionally)
+ future
+ .applyToEither(setTimeout(timeout, unit), handle)
+ .exceptionally(exceptionally)
+ .whenComplete(new BiConsumer[T, Throwable]() {
+ override def accept(t: T, u: Throwable): Unit = {
+ if (!future.isDone) {
+ future.cancel(true)
+ }
+ }
+ })
}
/**
@@ -75,36 +84,34 @@ object CompletableFutureUtils {
unit: TimeUnit,
handle: Consumer[T],
exceptionally: Consumer[Throwable]): CompletableFuture[Unit] = {
+
future.applyToEither(
setTimeout(timeout, unit),
- new JavaFunc[T, Unit] {
+ new JavaFunc[T, Unit]() {
override def apply(t: T): Unit = {
if (handle != null) {
handle.accept(t)
}
}
- }).exceptionally(new JavaFunc[Throwable, Unit] {
+ }).exceptionally(new JavaFunc[Throwable, Unit]() {
override def apply(t: Throwable): Unit = {
if (exceptionally != null) {
exceptionally.accept(t)
}
}
+ }).whenComplete(new BiConsumer[Unit, Throwable]() {
+ override def accept(t: Unit, u: Throwable): Unit = {
+ if (!future.isDone) {
+ future.cancel(true)
+ }
+ }
})
}
- def runTimeout[T](future: CompletableFuture[T], timeout: Long, unit: TimeUnit): CompletableFuture[Unit] = {
- runTimeout(
- future,
- timeout,
- unit,
- null,
- new Consumer[Throwable] {
- override def accept(t: Throwable): Unit = {
- if (!future.isDone) {
- future.cancel(true)
- }
- }
- })
+ def runTimeout[T](future: CompletableFuture[T],
+ timeout: Long,
+ unit: TimeUnit): CompletableFuture[Unit] = {
+ runTimeout(future, timeout, unit, null, null)
}
}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/MoreFutures.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/MoreFutures.java
deleted file mode 100644
index 78fbecf7b..000000000
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/MoreFutures.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.streampark.console.base.util;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.Delayed;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-public final class MoreFutures {
- private MoreFutures() {}
-
- public static <T> T await(CompletionStage<T> stage) {
- CompletableFuture<T> future = stage.toCompletableFuture();
-
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (ExecutionException e) {
- throw new RuntimeException(e.getCause());
- }
- }
-
- public static <T> T deref(CompletionStage<T> stage, long timeout, TimeUnit unit) {
- CompletableFuture<T> future = stage.toCompletableFuture();
-
- try {
- return future.get(timeout, unit);
- } catch (TimeoutException | InterruptedException e) {
- throw new RuntimeException(e);
- } catch (ExecutionException e) {
- throw new RuntimeException(e.getCause());
- }
- }
-
- public static <T> T derefUsingDefaultTimeout(CompletionStage<T> stage) {
- return deref(stage, 5L, TimeUnit.SECONDS);
- }
-
- public static <T> CompletionStage<T> exceptionallyCompose(
- CompletionStage<T> stage, Function<Throwable, ? extends CompletionStage<T>> fn) {
- return stage
- .thenApply(CompletableFuture::completedFuture)
- .exceptionally((Function<Throwable, ? extends CompletableFuture<T>>) fn)
- .thenCompose(Function.identity());
- }
-
- public static <T> CompletableFuture<T> completeImmediately(Supplier<T> supplier) {
- try {
- return CompletableFuture.completedFuture(supplier.get());
- } catch (Throwable e) {
- CompletableFuture<T> f = new CompletableFuture<>();
- f.completeExceptionally(e);
- return f;
- }
- }
-
- public static <T> CompletableFuture<T> completedExceptionally(Throwable cause) {
- CompletableFuture<T> future = new CompletableFuture<>();
- future.completeExceptionally(cause);
- return future;
- }
-
- public static <T> ScheduledFuture<T> completedScheduledFuture(T value) {
- return new CompletedScheduledFuture<>(value);
- }
-
- private static final class CompletedScheduledFuture<T> implements ScheduledFuture<T> {
- private final T value;
-
- private CompletedScheduledFuture(T value) {
- this.value = value;
- }
-
- public long getDelay(TimeUnit unit) {
- return 0L;
- }
-
- public int compareTo(Delayed o) {
- return Long.compare(0L, o.getDelay(TimeUnit.MILLISECONDS));
- }
-
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false;
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- public boolean isDone() {
- return true;
- }
-
- public T get() throws InterruptedException, ExecutionException {
- return this.value;
- }
-
- public T get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException {
- return this.value;
- }
- }
-}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
index 1683e208a..a580d7655 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
@@ -23,7 +23,6 @@ import org.apache.streampark.console.base.domain.ApiDocConstant;
import org.apache.streampark.console.base.domain.RestRequest;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.InternalException;
-import org.apache.streampark.console.base.util.MoreFutures;
import org.apache.streampark.console.core.annotation.ApiAccess;
import org.apache.streampark.console.core.bean.AppControl;
import org.apache.streampark.console.core.entity.Application;
@@ -34,7 +33,6 @@ import org.apache.streampark.console.core.service.AppBuildPipeService;
import org.apache.streampark.console.core.service.ApplicationBackUpService;
import org.apache.streampark.console.core.service.ApplicationLogService;
import org.apache.streampark.console.core.service.ApplicationService;
-import org.apache.streampark.console.core.service.LoggerService;
import org.apache.streampark.flink.packer.pipeline.PipelineStatus;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -48,7 +46,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;
@@ -77,8 +74,6 @@ public class ApplicationController {
@Autowired private AppBuildPipeService appBuildPipeService;
- @Autowired private LoggerService logService;
-
@ApiAccess
@PostMapping("get")
@RequiresPermissions("app:detail")
@@ -417,21 +412,13 @@ public class ApplicationController {
@ApiOperation(value = "Read flink on k8s deploy log")
@ApiImplicitParams({
- @ApiImplicitParam(name = "namespace", value = "ks8 namespace"),
- @ApiImplicitParam(name = "jobName", value = "job name"),
- @ApiImplicitParam(name = "jobId", value = "job id"),
- @ApiImplicitParam(name = "skipLineNum", value = "number of log lines skipped loading"),
+ @ApiImplicitParam(name = "id", value = "app id"),
+ @ApiImplicitParam(name = "offset", value = "number of log lines offset"),
@ApiImplicitParam(name = "limit", value = "number of log lines loaded at once")
})
- @PostMapping(value = "/detail")
- public RestResponse detail(
- @RequestParam(value = "namespace", required = false) String namespace,
- @RequestParam(value = "jobName", required = false) String jobName,
- @RequestParam(value = "jobId", required = false) String jobId,
- @RequestParam(value = "skipLineNum", required = false) Integer skipLineNum,
- @RequestParam(value = "limit", required = false) Integer limit) {
- return RestResponse.success(
- MoreFutures.derefUsingDefaultTimeout(
- logService.queryLog(namespace, jobName, jobId, skipLineNum, limit)));
+ @PostMapping(value = "k8sStartLog")
+ public RestResponse k8sStartLog(Long id, Integer offset, Integer limit) throws Exception {
+ String resp = applicationService.k8sStartLog(id, offset, limit);
+ return RestResponse.success(resp);
}
}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
index 1ab095855..87513f09b 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
@@ -113,4 +113,6 @@ public interface ApplicationService extends IService<Application> {
List<String> getRecentK8sTmPodTemplate();
List<String> historyUploadJars();
+
+ String k8sStartLog(Long id, Integer offset, Integer limit) throws Exception;
}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LogClientService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LogClientService.java
index 9b065b6c1..c9525ab64 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LogClientService.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LogClientService.java
@@ -17,14 +17,15 @@
package org.apache.streampark.console.core.service;
+import org.apache.streampark.console.base.exception.ApiDetailException;
+
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.File;
-import java.io.IOException;
+import java.io.FileNotFoundException;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -33,38 +34,21 @@ import java.util.stream.Stream;
@Slf4j
@Component
public class LogClientService {
- public String rollViewLog(String path, int skipLineNum, int limit) {
- String result = "";
+ public String rollViewLog(String path, int offset, int limit) {
try {
- List<String> lines = readPartFileContent(path, skipLineNum, limit);
- StringBuilder builder = new StringBuilder();
- lines.forEach(line -> builder.append(line).append("\r\n"));
- return builder.toString();
- } catch (Exception e) {
- log.error("roll view log error", e);
- }
- return result;
- }
-
- /**
- * read part file content,can skip any line and read some lines
- *
- * @param filePath file path
- * @param skipLine skip line
- * @param limit read lines limit
- * @return part file content
- */
- private List<String> readPartFileContent(String filePath, int skipLine, int limit) {
- File file = new File(filePath);
- if (file.exists() && file.isFile()) {
- try (Stream<String> stream = Files.lines(Paths.get(filePath))) {
- return stream.skip(skipLine).limit(limit).collect(Collectors.toList());
- } catch (IOException e) {
- log.error("read file error", e);
+ File file = new File(path);
+ if (file.exists() && file.isFile()) {
+ try (Stream<String> stream = Files.lines(Paths.get(path))) {
+ List<String> lines = stream.skip(offset).limit(limit).collect(Collectors.toList());
+ StringBuilder builder = new StringBuilder();
+ lines.forEach(line -> builder.append(line).append("\r\n"));
+ return builder.toString();
+ }
+ } else {
+ throw new FileNotFoundException("file path: " + path + " not exists ");
}
- } else {
- log.info("file path: {} not exists", filePath);
+ } catch (Exception e) {
+ throw new ApiDetailException("roll view log error: " + e);
}
- return Collections.emptyList();
}
}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LoggerService.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LoggerService.java
deleted file mode 100644
index 5e0df1ca4..000000000
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/LoggerService.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.streampark.console.core.service;
-
-import java.util.concurrent.CompletionStage;
-
-public interface LoggerService {
- CompletionStage<String> queryLog(
- String namespac, String jobName, String jobId, int skipLineNum, int limit);
-}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
index f10622d51..778dcfe67 100644
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
@@ -72,6 +72,7 @@ import org.apache.streampark.console.core.service.EffectiveService;
import org.apache.streampark.console.core.service.FlinkClusterService;
import org.apache.streampark.console.core.service.FlinkEnvService;
import org.apache.streampark.console.core.service.FlinkSqlService;
+import org.apache.streampark.console.core.service.LogClientService;
import org.apache.streampark.console.core.service.ProjectService;
import org.apache.streampark.console.core.service.SavePointService;
import org.apache.streampark.console.core.service.SettingService;
@@ -206,6 +207,8 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Appli
@Autowired private VariableService variableService;
+ @Autowired private LogClientService logClient;
+
@PostConstruct
public void resetOptionState() {
this.baseMapper.resetOptionState();
@@ -579,6 +582,43 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Appli
.collect(Collectors.toList());
}
+ @Override
+ public String k8sStartLog(Long id, Integer offset, Integer limit) throws Exception {
+ Application application = getById(id);
+ AssertUtils.state(application != null);
+ if (ExecutionMode.isKubernetesMode(application.getExecutionModeEnum())) {
+ CompletableFuture<String> future =
+ CompletableFuture.supplyAsync(
+ () ->
+ KubernetesDeploymentHelper.watchDeploymentLog(
+ application.getK8sNamespace(),
+ application.getJobName(),
+ application.getJobId()));
+
+ return CompletableFutureUtils.supplyTimeout(
+ future,
+ 5,
+ TimeUnit.SECONDS,
+ success -> success,
+ exception -> {
+ String errorLog =
+ String.format(
+ "%s/%s_err.log", WebUtils.getAppTempDir(), application.getJobId());
+ File file = new File(errorLog);
+ if (file.exists()) {
+ return errorLog;
+ } else {
+ throw new ApiDetailException("get k8s job log failed: " + exception.getMessage());
+ }
+ })
+ .thenApply(path -> logClient.rollViewLog(path, offset, limit))
+ .get();
+ } else {
+ throw new ApiAlertException(
+ "job executionMode must be kubernetes-session|kubernetes-application");
+ }
+ }
+
@Override
public String getYarnName(Application appParam) {
String[] args = new String[2];
@@ -1254,7 +1294,6 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Appli
IngressController.deleteIngress(
application.getK8sNamespace(), application.getJobName());
}
- cancelFuture.cancel(true);
cancelFutureMap.remove(application.getId());
});
}
@@ -1558,7 +1597,6 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Appli
})
.whenComplete(
(t, e) -> {
- future.cancel(true);
startFutureMap.remove(application.getId());
});
}
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/LoggerServiceImpl.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/LoggerServiceImpl.java
deleted file mode 100644
index ba1b8dd5d..000000000
--- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/LoggerServiceImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.streampark.console.core.service.impl;
-
-import org.apache.streampark.console.base.util.WebUtils;
-import org.apache.streampark.console.core.service.LogClientService;
-import org.apache.streampark.console.core.service.LoggerService;
-import org.apache.streampark.flink.kubernetes.helper.KubernetesDeploymentHelper;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-
-/** log service */
-@Service
-@Slf4j
-public class LoggerServiceImpl implements LoggerService {
-
- @Autowired private LogClientService logClient;
-
- /**
- * view log
- *
- * @param skipLineNum skip line number
- * @param limit limit
- * @return log string data
- */
- @Override
- public CompletionStage<String> queryLog(
- String nameSpace, String jobName, String jobId, int skipLineNum, int limit) {
- return CompletableFuture.supplyAsync(() -> jobDeploymentsWatch(nameSpace, jobName, jobId))
- .exceptionally(
- e -> {
- try {
- return String.format("%s/%s_err.log", WebUtils.getAppTempDir(), jobId);
- } catch (Exception ex) {
- log.error("Generate log path exception:{}", ex.getMessage());
- return null;
- }
- })
- .thenApply(path -> logClient.rollViewLog(String.valueOf(path), skipLineNum, limit));
- }
-
- private String jobDeploymentsWatch(String nameSpace, String jobName, String jobId) {
- return KubernetesDeploymentHelper.watchDeploymentLog(nameSpace, jobName, jobId);
- }
-}
diff --git a/streampark-console/streampark-console-service/src/test/java/java/util/concurrent/CompletableFutureTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/common/util/CompletableFutureUtilsTest.java
similarity index 66%
rename from streampark-console/streampark-console-service/src/test/java/java/util/concurrent/CompletableFutureTest.java
rename to streampark-console/streampark-console-service/src/test/java/org/apache/streampark/common/util/CompletableFutureUtilsTest.java
index 99838b55f..d6c226b74 100644
--- a/streampark-console/streampark-console-service/src/test/java/java/util/concurrent/CompletableFutureTest.java
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/common/util/CompletableFutureUtilsTest.java
@@ -15,16 +15,20 @@
* limitations under the License.
*/
-package java.util.concurrent;
-
-import org.apache.streampark.common.util.CompletableFutureUtils;
+package org.apache.streampark.common.util;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
-class CompletableFutureTest {
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class CompletableFutureUtilsTest {
@Test
void testStartJobNormally() throws Exception {
@@ -143,4 +147,73 @@ class CompletableFutureTest {
}
return "start successful";
}
+
+ @Test
+ public void thenFutureNormally() throws Exception {
+ String successResult = "success";
+ String exceptionResult = "error";
+
+ String resp =
+ CompletableFutureUtils.supplyTimeout(
+ CompletableFuture.supplyAsync(() -> successResult),
+ 1,
+ TimeUnit.SECONDS,
+ success -> success,
+ e -> exceptionResult)
+ .thenApply(r -> r)
+ .get();
+
+ Assertions.assertEquals(resp, successResult);
+ }
+
+ @Test
+ public void thenFutureTimeout() throws Exception {
+ String successResult = "success";
+ String exceptionResult = "error";
+ CompletableFuture<String> future =
+ CompletableFuture.supplyAsync(
+ () -> {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ return successResult;
+ });
+ String resp =
+ CompletableFutureUtils.supplyTimeout(
+ future, 1, TimeUnit.SECONDS, success -> success, e -> exceptionResult)
+ .thenApply(r -> r)
+ .get();
+ Assertions.assertEquals(resp, exceptionResult);
+ }
+
+ @Test
+ public void thenFutureException() {
+ String expectedExceptionMessage = "Exception in exceptionally handler";
+ int processTime = 5000;
+ int timeOut = 1000;
+ CompletableFuture<String> future =
+ CompletableFutureUtils.supplyTimeout(
+ CompletableFuture.supplyAsync(
+ () -> {
+ try {
+ Thread.sleep(processTime);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ return "success";
+ }),
+ timeOut,
+ TimeUnit.MILLISECONDS,
+ success -> success,
+ e -> {
+ throw new RuntimeException(expectedExceptionMessage);
+ });
+
+ assertThatThrownBy(future::get)
+ .getCause()
+ .as(expectedExceptionMessage)
+ .isInstanceOf(RuntimeException.class);
+ }
}
diff --git a/streampark-console/streampark-console-webapp/src/api/flink/app/app.ts b/streampark-console/streampark-console-webapp/src/api/flink/app/app.ts
index 958c2eb7a..054b22f33 100644
--- a/streampark-console/streampark-console-webapp/src/api/flink/app/app.ts
+++ b/streampark-console/streampark-console-webapp/src/api/flink/app/app.ts
@@ -25,7 +25,7 @@ enum APP_API {
UPDATE = '/flink/app/update',
COPY = '/flink/app/copy',
UPLOAD = '/flink/app/upload',
- START_LOG = '/flink/app/detail',
+ K8S_START_LOG = '/flink/app/k8sStartLog',
DEPLOY = '/flink/app/deploy',
MAPPING = '/flink/app/mapping',
YARN = '/flink/app/yarn',
@@ -188,8 +188,8 @@ export function fetchMapping(data): Promise<boolean> {
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
-export function fetchStartLog(data): Promise<AxiosResponse<any>> {
- return defHttp.post({ url: APP_API.START_LOG, data }, { isReturnNativeResponse: true });
+export function fetchK8sStartLog(data): Promise<AxiosResponse<any>> {
+ return defHttp.post({ url: APP_API.K8S_START_LOG, data }, { isReturnNativeResponse: true });
}
/**
* SavepointPath
diff --git a/streampark-console/streampark-console-webapp/src/views/flink/app/components/AppView/LogModal.vue b/streampark-console/streampark-console-webapp/src/views/flink/app/components/AppView/LogModal.vue
index 20ab2d608..29cd70417 100644
--- a/streampark-console/streampark-console-webapp/src/views/flink/app/components/AppView/LogModal.vue
+++ b/streampark-console/streampark-console-webapp/src/views/flink/app/components/AppView/LogModal.vue
@@ -24,7 +24,7 @@
</script>
<script setup lang="ts" name="LogModal">
import { reactive, ref, unref } from 'vue';
- import { fetchStartLog } from '/@/api/flink/app/app';
+ import { fetchK8sStartLog } from '/@/api/flink/app/app';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { Icon } from '/@/components/Icon';
import { formatToDateTime } from '/@/utils/dateUtil';
@@ -34,7 +34,7 @@
const logTime = ref<string>('');
const getLogLoading = ref<boolean>(false);
const app = reactive<Recordable>({});
- let skipLineNum = 0;
+ let offset = 0;
let logContent = '';
const [registerModal, { changeLoading, closeModal }] = useModalInner((data) => {
@@ -44,7 +44,7 @@
const { setContent, logRef, handleRevealLine, getLineCount } = useLog();
function onReceiveModalData(data) {
- skipLineNum = 0;
+ offset = 0;
logContent = '';
Object.assign(app, unref(data.app));
changeLoading(true);
@@ -63,12 +63,10 @@
async function refreshLog() {
try {
getLogLoading.value = true;
- const { data } = await fetchStartLog({
- namespace: app.k8sNamespace,
- jobName: app.jobName,
- jobId: app.jobId,
+ const { data } = await fetchK8sStartLog({
+ id: app.id,
+ offset: offset,
limit: 100,
- skipLineNum,
});
const status = data.status || 'error';
if (status === 'success') {
@@ -78,10 +76,10 @@
handleRevealLine();
setTimeout(() => {
const currentLineCount = getLineCount() - 1;
- if (currentLineCount < skipLineNum + 100) {
- skipLineNum = currentLineCount;
+ if (currentLineCount < offset + 100) {
+ offset = currentLineCount;
} else {
- skipLineNum += 100;
+ offset += 100;
}
}, 500);
}