diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebAsyncTaskInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebAsyncTaskInfo.java index 27ad56cb38..e168a54597 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebAsyncTaskInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebAsyncTaskInfo.java @@ -16,16 +16,19 @@ */ package io.cloudbeaver.model; +import org.jkiss.code.NotNull; import org.jkiss.dbeaver.model.runtime.AbstractJob; /** - * Web connection info + * Web async task info */ public class WebAsyncTaskInfo { - private String id; - private String name; - private boolean running; + @NotNull + private final String id; + @NotNull + private final String name; + private boolean running = false; private Object result; private Object extendedResult; private String status; @@ -33,27 +36,21 @@ public class WebAsyncTaskInfo { private AbstractJob job; - public WebAsyncTaskInfo(String id, String name) { + public WebAsyncTaskInfo(@NotNull String id, @NotNull String name) { this.id = id; this.name = name; } + @NotNull public String getId() { return id; } - public void setId(String id) { - this.id = id; - } - + @NotNull public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - public boolean isRunning() { return running; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 60a6fb1a8f..bc25ea310b 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -27,7 +27,6 @@ import io.cloudbeaver.model.app.ServletApplication; import io.cloudbeaver.model.app.ServletAuthApplication; import io.cloudbeaver.model.session.monitor.TaskProgressMonitor; -import io.cloudbeaver.model.session.monitor.TaskWithEventsProgressMonitor; import io.cloudbeaver.model.user.WebUser; import io.cloudbeaver.service.DBWSessionHandler; import io.cloudbeaver.service.sql.WebSQLConstants; @@ -66,6 +65,7 @@ import org.jkiss.dbeaver.model.websocket.event.MessageType; import org.jkiss.dbeaver.model.websocket.event.WSEventType; import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent; +import org.jkiss.dbeaver.model.websocket.event.session.WSSessionTaskInfoEvent; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.utils.CommonUtils; @@ -508,7 +508,7 @@ public DBRProgressMonitor getProgressMonitor() { /////////////////////////////////////////////////////// // Async model - public WebAsyncTaskInfo getAsyncTask(String taskId, String taskName, boolean create) { + public WebAsyncTaskInfo getAsyncTask(@NotNull String taskId, @NotNull String taskName, boolean create) { synchronized (asyncTasks) { WebAsyncTaskInfo taskInfo = asyncTasks.get(taskId); if (taskInfo == null && create) { @@ -525,7 +525,6 @@ public WebAsyncTaskInfo asyncTaskStatus(String taskId, boolean removeOnFinish) t if (taskInfo == null) { throw new DBWebException("Task '" + taskId + "' not found"); } - taskInfo.setRunning(taskInfo.getJob() != null && !taskInfo.getJob().isFinished()); if (removeOnFinish && !taskInfo.isRunning()) { asyncTasks.remove(taskId); } @@ -548,11 +547,7 @@ public boolean asyncTaskCancel(String taskId) throws DBWebException { return true; } - public WebAsyncTaskInfo createAndRunAsyncTask(String taskName, WebAsyncTaskProcessor runnable) { - return createAndRunAsyncTask(taskName, runnable, false); - } - - public WebAsyncTaskInfo createAndRunAsyncTask(String taskName, WebAsyncTaskProcessor runnable, boolean sendEvent) { + public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull WebAsyncTaskProcessor runnable) { int taskId = TASK_ID.incrementAndGet(); WebAsyncTaskInfo asyncTask = getAsyncTask(String.valueOf(taskId), taskName, true); @@ -561,9 +556,7 @@ public WebAsyncTaskInfo createAndRunAsyncTask(String taskName, WebAsyncTaskProce protected IStatus run(DBRProgressMonitor monitor) { int curTaskCount = taskCount.incrementAndGet(); - DBRProgressMonitor taskMonitor = sendEvent ? - new TaskWithEventsProgressMonitor(monitor, WebSession.this, asyncTask) : - new TaskProgressMonitor(monitor, asyncTask); + DBRProgressMonitor taskMonitor = new TaskProgressMonitor(monitor, WebSession.this, asyncTask); try { Number queryLimit = application.getAppConfiguration().getResourceQuota(WebSQLConstants.QUOTA_PROP_QUERY_LIMIT); @@ -576,7 +569,6 @@ protected IStatus run(DBRProgressMonitor monitor) { asyncTask.setResult(runnable.getResult()); asyncTask.setExtendedResult(runnable.getExtendedResults()); asyncTask.setStatus("Finished"); - asyncTask.setRunning(false); } catch (InvocationTargetException e) { addSessionError(e.getTargetException()); asyncTask.setJobError(e.getTargetException()); @@ -584,6 +576,8 @@ protected IStatus run(DBRProgressMonitor monitor) { asyncTask.setJobError(e); } finally { taskCount.decrementAndGet(); + asyncTask.setRunning(false); + addSessionEvent(WSSessionTaskInfoEvent.finish(asyncTask.getId())); } return Status.OK_STATUS; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskProgressMonitor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskProgressMonitor.java index a3de2db3b9..3d403d97ac 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskProgressMonitor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskProgressMonitor.java @@ -17,9 +17,11 @@ package io.cloudbeaver.model.session.monitor; import io.cloudbeaver.model.WebAsyncTaskInfo; +import io.cloudbeaver.model.session.WebSession; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.ProxyProgressMonitor; +import org.jkiss.dbeaver.model.websocket.event.session.WSSessionTaskInfoEvent; /** * Task progress monitor. @@ -29,9 +31,11 @@ public class TaskProgressMonitor extends ProxyProgressMonitor { @NotNull private final WebAsyncTaskInfo asyncTask; + private final WebSession webSession; - public TaskProgressMonitor(DBRProgressMonitor original, @NotNull WebAsyncTaskInfo asyncTask) { + public TaskProgressMonitor(DBRProgressMonitor original, @NotNull WebSession webSession, @NotNull WebAsyncTaskInfo asyncTask) { super(original); + this.webSession = webSession; this.asyncTask = asyncTask; } @@ -39,11 +43,13 @@ public TaskProgressMonitor(DBRProgressMonitor original, @NotNull WebAsyncTaskInf public void beginTask(String name, int totalWork) { super.beginTask(name, totalWork); asyncTask.setStatus(name); + webSession.addSessionEvent(WSSessionTaskInfoEvent.update(asyncTask.getId(), name)); } @Override public void subTask(String name) { super.subTask(name); asyncTask.setStatus(name); + webSession.addSessionEvent(WSSessionTaskInfoEvent.update(asyncTask.getId(), name)); } } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskWithEventsProgressMonitor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskWithEventsProgressMonitor.java deleted file mode 100644 index 475c3bc76f..0000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/monitor/TaskWithEventsProgressMonitor.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed 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 io.cloudbeaver.model.session.monitor; - -import io.cloudbeaver.model.WebAsyncTaskInfo; -import io.cloudbeaver.model.session.WebSession; -import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.exec.DBCException; -import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; -import org.jkiss.dbeaver.model.websocket.event.session.WSSessionTaskInfoEvent; - -import java.util.ArrayList; -import java.util.List; - -/** - * Task progress monitor with events. - * Can be used if we need to show a progress info in UI using web sockets. - */ -public class TaskWithEventsProgressMonitor extends TaskProgressMonitor { - private static final Log log = Log.getLog(TaskWithEventsProgressMonitor.class); - private final WebSession webSession; - private final List states = new ArrayList<>(); - - public TaskWithEventsProgressMonitor( - DBRProgressMonitor original, - @NotNull WebSession webSession, - @NotNull WebAsyncTaskInfo asyncTask - ) { - super(original, asyncTask); - this.webSession = webSession; - } - - @Override - public void beginTask(String name, int totalWork) { - super.beginTask(name, totalWork); - ProgressState progressState = new ProgressState(states.size(), name, totalWork); - states.add(progressState); - webSession.addSessionEvent(WSSessionTaskInfoEvent.start(progressState.id, name, progressState.totalWork)); - } - - @Override - public void subTask(String name) { - super.subTask(name); - if (states.isEmpty()) { - log.trace(new DBCException("Progress sub task without start")); - } else { - ProgressState progressState = states.get(states.size() - 1); - progressState.subTask = name; - webSession.addSessionEvent( - WSSessionTaskInfoEvent.update( - progressState.id, - name, - progressState.progress, - progressState.totalWork - ) - ); - } - } - - @Override - public void worked(int work) { - super.worked(work); - if (states.isEmpty()) { - log.trace(new DBCException("Progress info without start")); - } else { - ProgressState progressState = states.get(states.size() - 1); - progressState.progress += work; - webSession.addSessionEvent(WSSessionTaskInfoEvent.update( - progressState.id, - progressState.taskName, - progressState.progress, - progressState.totalWork - )); - } - } - - @Override - public void done() { - if (states.isEmpty()) { - log.trace(new DBCException("Progress ended without start")); - } else { - ProgressState progressState = states.get(states.size() - 1); - states.remove(states.size() - 1); - webSession.addSessionEvent(WSSessionTaskInfoEvent.finish(progressState.id, progressState.progress)); - } - super.done(); - // Restore previous state - if (!states.isEmpty()) { - ProgressState lastState = states.remove(states.size() - 1); - super.beginTask(lastState.taskName, lastState.totalWork); - if (lastState.subTask != null) { - super.subTask(lastState.subTask); - } - if (lastState.progress > 0) { - super.worked(lastState.progress); - } - } - } - - private static class ProgressState { - final String taskName; - final int id; - final int totalWork; - int progress; - String subTask; - - ProgressState(int id, String taskName, int totalWork) { - this.id = id; - this.taskName = taskName; - this.totalWork = totalWork; - } - } -} \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls index 3c506edd11..49fff71c64 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls @@ -30,7 +30,10 @@ enum CBServerEventId { cb_object_permissions_updated, cb_subject_permissions_updated, - cb_database_output_log_updated + cb_database_output_log_updated, + + cb_session_task_info_updated, @since(version: "24.3.1") + cb_session_task_info_finished @since(version: "24.3.1") } # Events sent by client @@ -53,7 +56,8 @@ enum CBEventTopic { cb_object_permissions, cb_subject_permissions, cb_database_output_log, - cb_delete_temp_folder + cb_delete_temp_folder, + cb_session_task @since(version: "24.3.1") } # Base server event interface @@ -178,6 +182,13 @@ type WSOutputLogInfo { # Add more fields as needed } +# Async task info status event +type WSAsyncTaskInfo @since(version: "24.3.1") { + id: CBServerEventId! + taskId: ID! + statusName: String +} + extend type Query { emptyEvent: Boolean }