Signed-off-by: Marcel Klehr <mklehr@gmx.net>pull/45094/head
@@ -114,8 +114,8 @@ class TaskProcessingApiController extends \OCP\AppFramework\OCSController { | |||
#[UserRateLimit(limit: 20, period: 120)] | |||
#[AnonRateLimit(limit: 5, period: 120)] | |||
#[ApiRoute(verb: 'POST', url: '/schedule', root: '/taskprocessing')] | |||
public function schedule(array $input, string $type, string $appId, string $identifier = ''): DataResponse { | |||
$task = new Task($type, $input, $appId, $this->userId, $identifier); | |||
public function schedule(array $input, string $type, string $appId, string $customId = ''): DataResponse { | |||
$task = new Task($type, $input, $appId, $this->userId, $customId); | |||
try { | |||
$this->taskProcessingManager->scheduleTask($task); | |||
@@ -200,7 +200,7 @@ namespace OCA\Core; | |||
* appId: string, | |||
* input: array<string, numeric|list<numeric>|string|list<string>>, | |||
* output: ?array<string, numeric|list<numeric>|string|list<string>>, | |||
* identifier: ?string, | |||
* customId: ?string, | |||
* completionExpectedAt: ?int, | |||
* progress: ?float | |||
* } |
@@ -31,7 +31,6 @@ use OCP\ILogger; | |||
use OCP\Log\IDataLogger; | |||
use Psr\Log\InvalidArgumentException; | |||
use Psr\Log\LoggerInterface; | |||
use Stringable; | |||
use Throwable; | |||
use function array_key_exists; | |||
use function array_merge; | |||
@@ -53,10 +52,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
/** | |||
* System is unusable. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function emergency(string|Stringable $message, array $context = []): void { | |||
public function emergency($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -76,10 +75,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* Example: Entire website down, database unavailable, etc. This should | |||
* trigger the SMS alerts and wake you up. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function alert(string|Stringable $message, array $context = []): void { | |||
public function alert($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -98,10 +97,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* | |||
* Example: Application component unavailable, unexpected exception. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function critical(string|Stringable $message, array $context = []): void { | |||
public function critical($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -119,10 +118,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* Runtime errors that do not require immediate action but should typically | |||
* be logged and monitored. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function error(string|Stringable $message, array $context = []): void { | |||
public function error($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -142,10 +141,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* Example: Use of deprecated APIs, poor use of an API, undesirable things | |||
* that are not necessarily wrong. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function warning(string|Stringable $message, array $context = []): void { | |||
public function warning($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -162,10 +161,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
/** | |||
* Normal but significant events. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function notice(string|Stringable $message, array $context = []): void { | |||
public function notice($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -184,10 +183,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* | |||
* Example: User logs in, SQL logs. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function info(string|Stringable $message, array $context = []): void { | |||
public function info($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -204,10 +203,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
/** | |||
* Detailed debug information. | |||
* | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
*/ | |||
public function debug(string|Stringable $message, array $context = []): void { | |||
public function debug($message, array $context = []): void { | |||
if ($this->containsThrowable($context)) { | |||
$this->logger->logException($context['exception'], array_merge( | |||
[ | |||
@@ -225,12 +224,12 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { | |||
* Logs with an arbitrary level. | |||
* | |||
* @param mixed $level | |||
* @param string|Stringable $message | |||
* @param $message | |||
* @param mixed[] $context | |||
* | |||
* @throws InvalidArgumentException | |||
*/ | |||
public function log($level, string|Stringable $message, array $context = []): void { | |||
public function log($level, $message, array $context = []): void { | |||
if (!is_int($level) || $level < ILogger::DEBUG || $level > ILogger::FATAL) { | |||
throw new InvalidArgumentException('Nextcloud allows only integer log levels'); | |||
} |
@@ -43,7 +43,7 @@ use OCP\TaskProcessing\Task as OCPTask; | |||
* @method string|null getUserId() | |||
* @method setAppId(string $type) | |||
* @method string getAppId() | |||
* @method setIdentifier(string $identifier) | |||
* @method setIdentifier(string $customId) | |||
* @method string getIdentifier() | |||
* @method setCompletionExpectedAt(null|\DateTime $completionExpectedAt) | |||
* @method null|\DateTime getCompletionExpectedAt() | |||
@@ -60,7 +60,7 @@ class Task extends Entity { | |||
protected $status; | |||
protected $userId; | |||
protected $appId; | |||
protected $identifier; | |||
protected $customId; | |||
protected $completionExpectedAt; | |||
protected $errorMessage; | |||
protected $progress; | |||
@@ -68,12 +68,12 @@ class Task extends Entity { | |||
/** | |||
* @var string[] | |||
*/ | |||
public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at', 'error_message', 'progress']; | |||
public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress']; | |||
/** | |||
* @var string[] | |||
*/ | |||
public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt', 'errorMessage', 'progress']; | |||
public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress']; | |||
public function __construct() { | |||
@@ -86,7 +86,7 @@ class Task extends Entity { | |||
$this->addType('status', 'integer'); | |||
$this->addType('userId', 'string'); | |||
$this->addType('appId', 'string'); | |||
$this->addType('identifier', 'string'); | |||
$this->addType('customId', 'string'); | |||
$this->addType('completionExpectedAt', 'datetime'); | |||
$this->addType('errorMessage', 'string'); | |||
$this->addType('progress', 'float'); | |||
@@ -110,7 +110,7 @@ class Task extends Entity { | |||
'errorMessage' => $task->getErrorMessage(), | |||
'userId' => $task->getUserId(), | |||
'appId' => $task->getAppId(), | |||
'identifier' => $task->getIdentifier(), | |||
'customId' => $task->getIdentifier(), | |||
'completionExpectedAt' => $task->getCompletionExpectedAt(), | |||
'progress' => $task->getProgress(), | |||
]); |
@@ -103,18 +103,18 @@ class TaskMapper extends QBMapper { | |||
/** | |||
* @param string $userId | |||
* @param string $appId | |||
* @param string|null $identifier | |||
* @param string|null $customId | |||
* @return list<Task> | |||
* @throws Exception | |||
*/ | |||
public function findUserTasksByApp(string $userId, string $appId, ?string $identifier = null): array { | |||
public function findUserTasksByApp(string $userId, string $appId, ?string $customId = null): array { | |||
$qb = $this->db->getQueryBuilder(); | |||
$qb->select(Task::$columns) | |||
->from($this->tableName) | |||
->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))) | |||
->andWhere($qb->expr()->eq('app_id', $qb->createPositionalParameter($appId))); | |||
if ($identifier !== null) { | |||
$qb->andWhere($qb->expr()->eq('identifier', $qb->createPositionalParameter($identifier))); | |||
if ($customId !== null) { | |||
$qb->andWhere($qb->expr()->eq('custom_id', $qb->createPositionalParameter($customId))); | |||
} | |||
return array_values($this->findEntities($qb)); | |||
} |
@@ -797,9 +797,9 @@ class Manager implements IManager { | |||
} | |||
} | |||
public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array { | |||
public function getUserTasksByApp(?string $userId, string $appId, ?string $customId = null): array { | |||
try { | |||
$taskEntities = $this->taskMapper->findUserTasksByApp($userId, $appId, $identifier); | |||
$taskEntities = $this->taskMapper->findUserTasksByApp($userId, $appId, $customId); | |||
return array_map(fn ($taskEntity): Task => $taskEntity->toPublicTask(), $taskEntities); | |||
} catch (\OCP\DB\Exception $e) { | |||
throw new \OCP\TaskProcessing\Exception\Exception('There was a problem finding a task', 0, $e); |
@@ -57,7 +57,7 @@ class SynchronousBackgroundJob extends QueuedJob { | |||
return; | |||
} | |||
try { | |||
$output = $provider->process($task->getUserId(), $input); | |||
$output = $provider->process($task->getUserId(), $input, fn(float $progress) => $this->taskProcessingManager->setTaskProgress($task->getId(), $progress)); | |||
} catch (ProcessingException $e) { | |||
$this->logger->warning('Failed to process a TaskProcessing task with synchronous provider ' . $provider->getId(), ['exception' => $e]); | |||
$this->taskProcessingManager->setTaskResult($task->getId(), $e->getMessage(), null); |
@@ -138,13 +138,13 @@ interface IManager { | |||
/** | |||
* @param string|null $userId | |||
* @param string $appId | |||
* @param string|null $identifier | |||
* @param string|null $customId | |||
* @return list<Task> | |||
* @throws Exception If the query failed | |||
* @throws \JsonException If parsing the task input and output failed | |||
* @since 30.0.0 | |||
*/ | |||
public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array; | |||
public function getUserTasksByApp(?string $userId, string $appId, ?string $customId = null): array; | |||
/** | |||
* Prepare the task's input data, so it can be processed by the provider |
@@ -41,9 +41,10 @@ interface ISynchronousProvider extends IProvider { | |||
* | |||
* @param null|string $userId The user that created the current task | |||
* @param array<string, list<numeric|string|File>|numeric|string|File> $input The task input | |||
* @param callable(float):bool $reportProgress Report the task progress. If this returns false, that means the task was cancelled and processing should be stopped. | |||
* @psalm-return array<string, list<numeric|string>|numeric|string> | |||
* @throws ProcessingException | |||
*@since 30.0.0 | |||
*/ | |||
public function process(?string $userId, array $input): array; | |||
public function process(?string $userId, array $input, callable $reportProgress): array; | |||
} |
@@ -79,7 +79,7 @@ final class Task implements \JsonSerializable { | |||
* @param array<string,list<numeric|string>|numeric|string> $input | |||
* @param string $appId | |||
* @param string|null $userId | |||
* @param null|string $identifier An arbitrary identifier for this task. max length: 255 chars | |||
* @param null|string $customId An arbitrary customId for this task. max length: 255 chars | |||
* @since 30.0.0 | |||
*/ | |||
final public function __construct( | |||
@@ -87,7 +87,7 @@ final class Task implements \JsonSerializable { | |||
protected array $input, | |||
protected readonly string $appId, | |||
protected readonly ?string $userId, | |||
protected readonly ?string $identifier = '', | |||
protected readonly ?string $customId = '', | |||
) { | |||
} | |||
@@ -182,8 +182,8 @@ final class Task implements \JsonSerializable { | |||
* @return null|string | |||
* @since 30.0.0 | |||
*/ | |||
final public function getIdentifier(): ?string { | |||
return $this->identifier; | |||
final public function getCustomId(): ?string { | |||
return $this->customId; | |||
} | |||
/** | |||
@@ -195,7 +195,7 @@ final class Task implements \JsonSerializable { | |||
} | |||
/** | |||
* @psalm-return array{id: ?int, type: string, status: 'STATUS_CANCELLED'|'STATUS_FAILED'|'STATUS_SUCCESSFUL'|'STATUS_RUNNING'|'STATUS_SCHEDULED'|'STATUS_UNKNOWN', userId: ?string, appId: string, input: array<array-key, list<numeric|string>|numeric|string>, output: ?array<array-key, list<numeric|string>|numeric|string>, identifier: ?string, completionExpectedAt: ?int, progress: ?float} | |||
* @psalm-return array{id: ?int, type: string, status: 'STATUS_CANCELLED'|'STATUS_FAILED'|'STATUS_SUCCESSFUL'|'STATUS_RUNNING'|'STATUS_SCHEDULED'|'STATUS_UNKNOWN', userId: ?string, appId: string, input: array<array-key, list<numeric|string>|numeric|string>, output: ?array<array-key, list<numeric|string>|numeric|string>, customId: ?string, completionExpectedAt: ?int, progress: ?float} | |||
* @since 30.0.0 | |||
*/ | |||
final public function jsonSerialize(): array { | |||
@@ -207,7 +207,7 @@ final class Task implements \JsonSerializable { | |||
'appId' => $this->getAppId(), | |||
'input' => $this->getInput(), | |||
'output' => $this->getOutput(), | |||
'identifier' => $this->getIdentifier(), | |||
'customId' => $this->getCustomId(), | |||
'completionExpectedAt' => $this->getCompletionExpectedAt()?->getTimestamp(), | |||
'progress' => $this->getProgress(), | |||
]; |