RDCT-1444 Add TaskStorage implementations for frontend.split and backend

`TaskStorage` service is responsible for storing/updating/removing tasks from Rhizome DB.
There are two implementations of the service - backend (available in mononlith and backend.split) and frontend.split

The backend implementation stores `TaskInfoEntity` into a shared partition of DB, so the tasks can be available both on backend and all connected frontends.

Frontend split implementation stores `TaskInfoEntity` into a local partition of DB, so the tasks produced by one of the frontends won't be available for backend or other frontends.
Consider "Code With Me" case here: when one of the guests starts some tasks, it shouldn't be visible to other guests.
However, if the host starts a task - all guests should see it.

GitOrigin-RevId: a020d871d2f5f88809dfed551f511b116e8ff550
This commit is contained in:
Kate Botsman
2024-08-19 17:20:08 +02:00
committed by intellij-monorepo-bot
parent 399c412ee6
commit 0e43a1e2dd
4 changed files with 160 additions and 0 deletions

View File

@@ -10,5 +10,8 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
<orderEntry type="module" module-name="intellij.platform.ide.progress" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="module" module-name="intellij.platform.core" />
</component>
</module>

View File

@@ -3,4 +3,12 @@
<!--The plugin won't be included in frontend-only builds-->
<plugin id="com.intellij.platform.experimental.backend"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<!-- IJPL-149684 -->
<!--suppress PluginXmlRegistrationCheck -->
<applicationService serviceInterface="com.intellij.platform.ide.progress.TaskStorage"
serviceImplementation="com.intellij.platform.progress.backend.BackendTaskStorage" />
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,37 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.progress.backend
import com.intellij.platform.ide.progress.TaskInfoEntity
import com.intellij.platform.ide.progress.TaskStorage
import com.jetbrains.rhizomedb.ChangeScope
import fleet.kernel.change
import fleet.kernel.delete
import fleet.kernel.shared
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class BackendTaskStorage : TaskStorage() {
override suspend fun createTaskInfoEntity(provider: ChangeScope.() -> TaskInfoEntity): TaskInfoEntity {
return change {
shared {
provider()
}
}
}
override suspend fun removeTaskInfoEntity(taskInfoEntity: TaskInfoEntity) {
change {
shared {
delete(taskInfoEntity)
}
}
}
override suspend fun updateTaskInfoEntity(updater: ChangeScope.() -> Unit) {
change {
shared {
updater()
}
}
}
}

View File

@@ -0,0 +1,112 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.progress
import com.intellij.openapi.components.service
import com.intellij.platform.kernel.KernelService
import com.intellij.platform.util.progress.ProgressState
import com.jetbrains.rhizomedb.ChangeScope
import fleet.kernel.withEntities
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.ApiStatus
/**
* Provides the ability to control how tasks are stored in Rhizome DB
* The implementation can decide where to store an object - in shared or local DB
* See [fleet.kernel.change] and [fleet.kernel.shared]
*/
@ApiStatus.Internal
abstract class TaskStorage {
/**
* Adds a new task to the storage and returns the created [TaskInfoEntity].
*
* @param title The title of the task.
* @param cancellation Specifies if the task can be canceled.
* @return The created [TaskInfoEntity].
*/
suspend fun addTask(
title: String,
cancellation: TaskCancellation,
): TaskInfoEntity = withContext(KernelService.kernelCoroutineContext()) {
createTaskInfoEntity {
TaskInfoEntity.new {
it[TaskInfoEntity.Title] = title
it[TaskInfoEntity.TaskCancellationType] = cancellation
it[TaskInfoEntity.ProgressStateType] = null
it[TaskInfoEntity.TaskStatusType] = TaskStatus.RUNNING
}
}
}
/**
* Creates a new [TaskInfoEntity] using [provider] lambda
* The implementation can decide whether the entity should be created locally on in the shared DB scope.
*
* It's guaranteed that the method is called in the correct coroutine context,
* which includes kernel (see [KernelService.kernelCoroutineContext])
*
* @param provider The provider used to create the [TaskInfoEntity].
* @return The created [TaskInfoEntity].
*/
protected abstract suspend fun createTaskInfoEntity(provider: ChangeScope.() -> TaskInfoEntity): TaskInfoEntity
/**
* Removes a task from Rhizome DB.
* NOTE: this doesn't cancel a running task, to cancel a task use [TaskManager.cancelTask]
*
* @param taskInfoEntity The task to be removed.
*/
suspend fun removeTask(taskInfoEntity: TaskInfoEntity): Unit = withContext(KernelService.kernelCoroutineContext()) {
withEntities(taskInfoEntity) {
removeTaskInfoEntity(taskInfoEntity)
}
}
/**
* Removes the specified task from the storage.
* The implementation should use the same scope as in [createTaskInfoEntity] to remove the entity.
*
* It's guaranteed that only the task created by this instance of [TaskStorage]
* are going to be passed to this method.
*
* It is also guaranteed that the method is called in the correct coroutine context,
* which includes kernel (see [KernelService.kernelCoroutineContext])
*
* @param taskInfoEntity The task entity to be removed.
*/
protected abstract suspend fun removeTaskInfoEntity(taskInfoEntity: TaskInfoEntity)
/**
* Updates the progress state of the given task.
* Old state is going to be overwritten, to receive all state updates use [updates]
*
* @param taskInfoEntity The task to be updated.
* @param state The new progress state to set on the task.
* @return Unit
*/
suspend fun updateTask(taskInfoEntity: TaskInfoEntity, state: ProgressState): Unit = withContext(KernelService.kernelCoroutineContext()) {
withEntities(taskInfoEntity) {
updateTaskInfoEntity {
taskInfoEntity[TaskInfoEntity.ProgressStateType] = state
}
}
}
/**
* Updates a [TaskInfoEntity] in the storage using provided [updater]
*
* It's guaranteed that only the task created by this instance of [TaskStorage]
* are going to be passed to this method.
*
* It is also guaranteed that the method is called in the correct coroutine context,
* which includes kernel (see [KernelService.kernelCoroutineContext])
*
* @param updater A lambda provided with a [ChangeScope] receiver to modify the task information.
*/
protected abstract suspend fun updateTaskInfoEntity(updater: ChangeScope.() -> Unit)
companion object {
@JvmStatic
fun getInstance(): TaskStorage = service()
}
}