adds scheduling commit, still need to resolve pools error
This commit is contained in:
parent
396ff87fbc
commit
b8aa2faa7b
|
@ -80,6 +80,7 @@ RUN chmod +x /usr/local/bin/doctor && \
|
||||||
chmod +x /usr/local/bin/migrate && \
|
chmod +x /usr/local/bin/migrate && \
|
||||||
chmod +x /usr/local/bin/realtime && \
|
chmod +x /usr/local/bin/realtime && \
|
||||||
chmod +x /usr/local/bin/schedule && \
|
chmod +x /usr/local/bin/schedule && \
|
||||||
|
chmod +x /usr/local/bin/schedule-message && \
|
||||||
chmod +x /usr/local/bin/sdks && \
|
chmod +x /usr/local/bin/sdks && \
|
||||||
chmod +x /usr/local/bin/specs && \
|
chmod +x /usr/local/bin/specs && \
|
||||||
chmod +x /usr/local/bin/ssl && \
|
chmod +x /usr/local/bin/ssl && \
|
||||||
|
|
|
@ -1593,6 +1593,28 @@ $commonCollections = [
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => ['datetime'],
|
'filters' => ['datetime'],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('scheduleInternalId'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('scheduleId'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('deliveredAt'),
|
'$id' => ID::custom('deliveredAt'),
|
||||||
'type' => Database::VAR_DATETIME,
|
'type' => Database::VAR_DATETIME,
|
||||||
|
@ -4166,6 +4188,13 @@ $consoleCollections = array_merge([
|
||||||
'lengths' => [],
|
'lengths' => [],
|
||||||
'orders' => [],
|
'orders' => [],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('_key_schedule_resourceType_active_resourceUpdatedAt'),
|
||||||
|
'type' => Database::INDEX_KEY,
|
||||||
|
'attributes' => ['schedule', 'resourceType', 'active', 'resourceUpdatedAt'],
|
||||||
|
'lengths' => [],
|
||||||
|
'orders' => [],
|
||||||
|
]
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -1375,7 +1375,6 @@ App::post('/v1/account/sessions/phone')
|
||||||
->setMessage($messageDoc)
|
->setMessage($messageDoc)
|
||||||
->setRecipients([$phone])
|
->setRecipients([$phone])
|
||||||
->setProviderType(MESSAGE_TYPE_SMS)
|
->setProviderType(MESSAGE_TYPE_SMS)
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
|
|
||||||
$queueForEvents->setPayload(
|
$queueForEvents->setPayload(
|
||||||
|
@ -3101,7 +3100,6 @@ App::post('/v1/account/verification/phone')
|
||||||
->setMessage($messageDoc)
|
->setMessage($messageDoc)
|
||||||
->setRecipients([$user->getAttribute('phone')])
|
->setRecipients([$user->getAttribute('phone')])
|
||||||
->setProviderType(MESSAGE_TYPE_SMS)
|
->setProviderType(MESSAGE_TYPE_SMS)
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
|
|
@ -34,6 +34,7 @@ use Utopia\Validator\Boolean;
|
||||||
use Utopia\Validator\JSON;
|
use Utopia\Validator\JSON;
|
||||||
use Utopia\Validator\Text;
|
use Utopia\Validator\Text;
|
||||||
use MaxMind\Db\Reader;
|
use MaxMind\Db\Reader;
|
||||||
|
use Utopia\Database\DateTime;
|
||||||
use Utopia\Validator\WhiteList;
|
use Utopia\Validator\WhiteList;
|
||||||
|
|
||||||
use function Swoole\Coroutine\batch;
|
use function Swoole\Coroutine\batch;
|
||||||
|
@ -1441,7 +1442,6 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
|
||||||
->label('audits.resource', 'provider/{response.$id}')
|
->label('audits.resource', 'provider/{response.$id}')
|
||||||
->label('event', 'providers.[providerId].update')
|
->label('event', 'providers.[providerId].update')
|
||||||
->label('scope', 'providers.write')
|
->label('scope', 'providers.write')
|
||||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
|
||||||
->label('sdk.namespace', 'messaging')
|
->label('sdk.namespace', 'messaging')
|
||||||
->label('sdk.method', 'updateFcmProvider')
|
->label('sdk.method', 'updateFcmProvider')
|
||||||
->label('sdk.description', '/docs/references/messaging/update-fcm-provider.md')
|
->label('sdk.description', '/docs/references/messaging/update-fcm-provider.md')
|
||||||
|
@ -2228,10 +2228,11 @@ App::post('/v1/messaging/messages/email')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
||||||
|
|
||||||
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
||||||
|
@ -2245,6 +2246,7 @@ App::post('/v1/messaging/messages/email')
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'targets' => $targets,
|
'targets' => $targets,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
|
'scheduledAt' => $scheduledAt,
|
||||||
'data' => [
|
'data' => [
|
||||||
'subject' => $subject,
|
'subject' => $subject,
|
||||||
'content' => $content,
|
'content' => $content,
|
||||||
|
@ -2253,11 +2255,24 @@ App::post('/v1/messaging/messages/email')
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && $scheduledAt === null) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
|
} else if ($scheduledAt !== null) {
|
||||||
|
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||||
|
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||||
|
'resourceType' => 'message',
|
||||||
|
'resourceId' => $message->getId(),
|
||||||
|
'resourceInternalId' => $message->getInternalId(),
|
||||||
|
'resourceUpdatedAt' => DateTime::now(),
|
||||||
|
'projectId' => $project->getId(),
|
||||||
|
'schedule' => $message->getAttribute('scheduledAt'),
|
||||||
|
'active' => $status === 'processing' ? true : false,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$message->setAttribute('scheduleId', $schedule->getId());
|
||||||
|
$dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
@ -2292,10 +2307,11 @@ App::post('/v1/messaging/messages/sms')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
||||||
|
|
||||||
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
||||||
|
@ -2315,11 +2331,24 @@ App::post('/v1/messaging/messages/sms')
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && $scheduledAt === null) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
|
} else if ($status === 'processing' && $scheduledAt !== null) {
|
||||||
|
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||||
|
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||||
|
'resourceType' => 'message',
|
||||||
|
'resourceId' => $message->getId(),
|
||||||
|
'resourceInternalId' => $message->getInternalId(),
|
||||||
|
'resourceUpdatedAt' => DateTime::now(),
|
||||||
|
'projectId' => $project->getId(),
|
||||||
|
'schedule' => $message->getAttribute('scheduledAt'),
|
||||||
|
'active' => $status === 'processing' ? true : false,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$message->setAttribute('scheduleId', $schedule->getId());
|
||||||
|
$dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
@ -2362,10 +2391,11 @@ App::post('/v1/messaging/messages/push')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
$messageId = $messageId == 'unique()' ? ID::unique() : $messageId;
|
||||||
|
|
||||||
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
|
||||||
|
@ -2394,11 +2424,24 @@ App::post('/v1/messaging/messages/push')
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && $scheduledAt === null) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
|
} else if ($status === 'processing' && $scheduledAt !== null) {
|
||||||
|
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||||
|
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||||
|
'resourceType' => 'message',
|
||||||
|
'resourceId' => $message->getId(),
|
||||||
|
'resourceInternalId' => $message->getInternalId(),
|
||||||
|
'resourceUpdatedAt' => DateTime::now(),
|
||||||
|
'projectId' => $project->getId(),
|
||||||
|
'schedule' => $message->getAttribute('scheduledAt'),
|
||||||
|
'active' => $status === 'processing' ? true : false,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$message->setAttribute('scheduleId', $schedule->getId());
|
||||||
|
$dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
@ -2586,10 +2629,11 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$message = $dbForProject->getDocument('messages', $messageId);
|
$message = $dbForProject->getDocument('messages', $messageId);
|
||||||
|
|
||||||
if ($message->isEmpty()) {
|
if ($message->isEmpty()) {
|
||||||
|
@ -2642,14 +2686,25 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
||||||
|
|
||||||
if (!is_null($scheduledAt)) {
|
if (!is_null($scheduledAt)) {
|
||||||
$message->setAttribute('scheduledAt', $scheduledAt);
|
$message->setAttribute('scheduledAt', $scheduledAt);
|
||||||
|
|
||||||
|
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
|
||||||
|
|
||||||
|
$schedule
|
||||||
|
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||||
|
->setAttribute('schedule', $message->getAttribute('schedule'));
|
||||||
|
|
||||||
|
if ($message->getAttribute('status') === 'processing') {
|
||||||
|
$schedule->setAttribute('active', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && \is_null($message->getAttribute('scheduledAt'))) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2684,10 +2739,11 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$message = $dbForProject->getDocument('messages', $messageId);
|
$message = $dbForProject->getDocument('messages', $messageId);
|
||||||
|
|
||||||
if ($message->isEmpty()) {
|
if ($message->isEmpty()) {
|
||||||
|
@ -2732,14 +2788,25 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
||||||
|
|
||||||
if (!is_null($scheduledAt)) {
|
if (!is_null($scheduledAt)) {
|
||||||
$message->setAttribute('scheduledAt', $scheduledAt);
|
$message->setAttribute('scheduledAt', $scheduledAt);
|
||||||
|
|
||||||
|
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
|
||||||
|
|
||||||
|
$schedule
|
||||||
|
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||||
|
->setAttribute('schedule', $message->getAttribute('schedule'));
|
||||||
|
|
||||||
|
if ($message->getAttribute('status') === 'processing') {
|
||||||
|
$schedule->setAttribute('active', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && \is_null($message->getAttribute('scheduledAt'))) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2781,10 +2848,11 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
||||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('dbForConsole')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('queueForMessaging')
|
->inject('queueForMessaging')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) {
|
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||||
$message = $dbForProject->getDocument('messages', $messageId);
|
$message = $dbForProject->getDocument('messages', $messageId);
|
||||||
|
|
||||||
if ($message->isEmpty()) {
|
if ($message->isEmpty()) {
|
||||||
|
@ -2861,16 +2929,27 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
||||||
|
|
||||||
if (!is_null($scheduledAt)) {
|
if (!is_null($scheduledAt)) {
|
||||||
$message->setAttribute('scheduledAt', $scheduledAt);
|
$message->setAttribute('scheduledAt', $scheduledAt);
|
||||||
|
|
||||||
|
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
|
||||||
|
|
||||||
|
$schedule
|
||||||
|
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||||
|
->setAttribute('schedule', $message->getAttribute('schedule'));
|
||||||
|
|
||||||
|
if ($message->getAttribute('status') === 'processing') {
|
||||||
|
$schedule->setAttribute('active', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||||
|
|
||||||
if ($status === 'processing') {
|
if ($status === 'processing' && \is_null($message->getAttribute('scheduledAt'))) {
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessageId($message->getId())
|
->setMessageId($message->getId())
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
->setParam('messageId', $message->getId());
|
->setParam('messageId', $message->getId());
|
||||||
|
|
|
@ -653,7 +653,6 @@ App::post('/v1/teams/:teamId/memberships')
|
||||||
->setMessage($messageDoc)
|
->setMessage($messageDoc)
|
||||||
->setRecipients([$phone])
|
->setRecipients([$phone])
|
||||||
->setProviderType('SMS')
|
->setProviderType('SMS')
|
||||||
->setProject($project)
|
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Appwrite\Event\Delete;
|
||||||
use Appwrite\Event\Event;
|
use Appwrite\Event\Event;
|
||||||
use Appwrite\Event\Func;
|
use Appwrite\Event\Func;
|
||||||
use Appwrite\Event\Mail;
|
use Appwrite\Event\Mail;
|
||||||
|
use Appwrite\Event\Messaging;
|
||||||
use Appwrite\Extend\Exception;
|
use Appwrite\Extend\Exception;
|
||||||
use Appwrite\Messaging\Adapter\Realtime;
|
use Appwrite\Messaging\Adapter\Realtime;
|
||||||
use Appwrite\Usage\Stats;
|
use Appwrite\Usage\Stats;
|
||||||
|
@ -97,6 +98,7 @@ App::init()
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('user')
|
->inject('user')
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
|
->inject('queueForMessaging')
|
||||||
->inject('queueForAudits')
|
->inject('queueForAudits')
|
||||||
->inject('queueForDeletes')
|
->inject('queueForDeletes')
|
||||||
->inject('queueForDatabase')
|
->inject('queueForDatabase')
|
||||||
|
@ -104,7 +106,7 @@ App::init()
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->inject('queueForMails')
|
->inject('queueForMails')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Database $dbForProject, string $mode, Mail $queueForMails, Stats $usage) use ($databaseListener) {
|
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Database $dbForProject, string $mode, Mail $queueForMails, Stats $usage) use ($databaseListener) {
|
||||||
|
|
||||||
$route = $utopia->getRoute();
|
$route = $utopia->getRoute();
|
||||||
|
|
||||||
|
@ -178,6 +180,9 @@ App::init()
|
||||||
->setProject($project)
|
->setProject($project)
|
||||||
->setUser($user);
|
->setUser($user);
|
||||||
|
|
||||||
|
$queueForMessaging
|
||||||
|
->setProject($project);
|
||||||
|
|
||||||
$queueForAudits
|
$queueForAudits
|
||||||
->setMode($mode)
|
->setMode($mode)
|
||||||
->setUserAgent($request->getUserAgent(''))
|
->setUserAgent($request->getUserAgent(''))
|
||||||
|
|
3
bin/schedule-message
Normal file
3
bin/schedule-message
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
php /usr/src/code/app/cli.php schedule-message $@
|
50
composer.lock
generated
50
composer.lock
generated
|
@ -402,16 +402,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "7.8.0",
|
"version": "7.8.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/guzzle.git",
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
"reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9"
|
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9",
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
|
||||||
"reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9",
|
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -426,11 +426,11 @@
|
||||||
"psr/http-client-implementation": "1.0"
|
"psr/http-client-implementation": "1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.1",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
|
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
|
||||||
"php-http/message-factory": "^1.1",
|
"php-http/message-factory": "^1.1",
|
||||||
"phpunit/phpunit": "^8.5.29 || ^9.5.23",
|
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
|
||||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
@ -508,7 +508,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||||
"source": "https://github.com/guzzle/guzzle/tree/7.8.0"
|
"source": "https://github.com/guzzle/guzzle/tree/7.8.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -524,28 +524,28 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-27T10:20:53+00:00"
|
"time": "2023-12-03T20:35:24+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/promises.git",
|
"url": "https://github.com/guzzle/promises.git",
|
||||||
"reference": "111166291a0f8130081195ac4556a5587d7f1b5d"
|
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d",
|
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
|
||||||
"reference": "111166291a0f8130081195ac4556a5587d7f1b5d",
|
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2.5 || ^8.0"
|
"php": "^7.2.5 || ^8.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.1",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"phpunit/phpunit": "^8.5.29 || ^9.5.23"
|
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
|
@ -591,7 +591,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/promises/issues",
|
"issues": "https://github.com/guzzle/promises/issues",
|
||||||
"source": "https://github.com/guzzle/promises/tree/2.0.1"
|
"source": "https://github.com/guzzle/promises/tree/2.0.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -607,20 +607,20 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-03T15:11:55+00:00"
|
"time": "2023-12-03T20:19:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "2.6.1",
|
"version": "2.6.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/psr7.git",
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
"reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727"
|
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727",
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
||||||
"reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727",
|
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -634,9 +634,9 @@
|
||||||
"psr/http-message-implementation": "1.0"
|
"psr/http-message-implementation": "1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.1",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"http-interop/http-factory-tests": "^0.9",
|
"http-interop/http-factory-tests": "^0.9",
|
||||||
"phpunit/phpunit": "^8.5.29 || ^9.5.23"
|
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||||
|
@ -707,7 +707,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/psr7/issues",
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
"source": "https://github.com/guzzle/psr7/tree/2.6.1"
|
"source": "https://github.com/guzzle/psr7/tree/2.6.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -723,7 +723,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-27T10:13:57+00:00"
|
"time": "2023-12-03T20:05:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "influxdb/influxdb-php",
|
"name": "influxdb/influxdb-php",
|
||||||
|
@ -5823,5 +5823,5 @@
|
||||||
"platform-overrides": {
|
"platform-overrides": {
|
||||||
"php": "8.0"
|
"php": "8.0"
|
||||||
},
|
},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -717,6 +717,33 @@ services:
|
||||||
- _APP_DB_USER
|
- _APP_DB_USER
|
||||||
- _APP_DB_PASS
|
- _APP_DB_PASS
|
||||||
|
|
||||||
|
appwrite-schedule-message:
|
||||||
|
entrypoint: schedule-message
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-schedule-message
|
||||||
|
image: appwrite-dev
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
volumes:
|
||||||
|
- ./app:/usr/src/code/app
|
||||||
|
- ./src:/usr/src/code/src
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
|
||||||
appwrite-assistant:
|
appwrite-assistant:
|
||||||
container_name: appwrite-assistant
|
container_name: appwrite-assistant
|
||||||
image: appwrite/assistant:0.2.2
|
image: appwrite/assistant:0.2.2
|
||||||
|
|
|
@ -20,6 +20,7 @@ use Appwrite\Platform\Tasks\CalcTierStats;
|
||||||
use Appwrite\Platform\Tasks\Upgrade;
|
use Appwrite\Platform\Tasks\Upgrade;
|
||||||
use Appwrite\Platform\Tasks\DeleteOrphanedProjects;
|
use Appwrite\Platform\Tasks\DeleteOrphanedProjects;
|
||||||
use Appwrite\Platform\Tasks\PatchRecreateRepositoriesDocuments;
|
use Appwrite\Platform\Tasks\PatchRecreateRepositoriesDocuments;
|
||||||
|
use Appwrite\Platform\Tasks\ScheduleMessage;
|
||||||
|
|
||||||
class Tasks extends Service
|
class Tasks extends Service
|
||||||
{
|
{
|
||||||
|
@ -36,6 +37,7 @@ class Tasks extends Service
|
||||||
->addAction(Install::getName(), new Install())
|
->addAction(Install::getName(), new Install())
|
||||||
->addAction(Upgrade::getName(), new Upgrade())
|
->addAction(Upgrade::getName(), new Upgrade())
|
||||||
->addAction(Maintenance::getName(), new Maintenance())
|
->addAction(Maintenance::getName(), new Maintenance())
|
||||||
|
->addAction(ScheduleMessage::getName(), new ScheduleMessage())
|
||||||
->addAction(Schedule::getName(), new Schedule())
|
->addAction(Schedule::getName(), new Schedule())
|
||||||
->addAction(Migrate::getName(), new Migrate())
|
->addAction(Migrate::getName(), new Migrate())
|
||||||
->addAction(SDKs::getName(), new SDKs())
|
->addAction(SDKs::getName(), new SDKs())
|
||||||
|
|
|
@ -85,7 +85,7 @@ class Maintenance extends Action
|
||||||
|
|
||||||
private function notifyDeleteUsageStats(int $usageStatsRetentionHourly, Delete $queueForDeletes): void
|
private function notifyDeleteUsageStats(int $usageStatsRetentionHourly, Delete $queueForDeletes): void
|
||||||
{
|
{
|
||||||
($queueForDeletes)
|
($queueFor)
|
||||||
->setType(DELETE_TYPE_USAGE)
|
->setType(DELETE_TYPE_USAGE)
|
||||||
->setUsageRetentionHourlyDateTime(DateTime::addSeconds(new \DateTime(), -1 * $usageStatsRetentionHourly))
|
->setUsageRetentionHourlyDateTime(DateTime::addSeconds(new \DateTime(), -1 * $usageStatsRetentionHourly))
|
||||||
->trigger();
|
->trigger();
|
||||||
|
|
164
src/Appwrite/Platform/Tasks/ScheduleMessage.php
Normal file
164
src/Appwrite/Platform/Tasks/ScheduleMessage.php
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\Platform\Tasks;
|
||||||
|
|
||||||
|
use Appwrite\Event\Delete;
|
||||||
|
use Swoole\Timer;
|
||||||
|
use Utopia\Platform\Action;
|
||||||
|
use Utopia\CLI\Console;
|
||||||
|
use Utopia\Database\DateTime;
|
||||||
|
use Utopia\Database\Query;
|
||||||
|
use Utopia\Database\Database;
|
||||||
|
use Utopia\Pools\Group;
|
||||||
|
use Appwrite\Event\Messaging;
|
||||||
|
|
||||||
|
use function Swoole\Coroutine\run;
|
||||||
|
|
||||||
|
class ScheduleMessage extends Action
|
||||||
|
{
|
||||||
|
public const MESSAGE_UPDATE_TIMER = 10; //seconds
|
||||||
|
public const MESSAGE_ENQUEUE_TIMER = 60; //seconds
|
||||||
|
|
||||||
|
public static function getName(): string
|
||||||
|
{
|
||||||
|
return 'schedule-message';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->desc('Execute functions scheduled in Appwrite')
|
||||||
|
->inject('pools')
|
||||||
|
->inject('dbForConsole')
|
||||||
|
->inject('getProjectDB')
|
||||||
|
->callback(fn (Group $pools, Database $dbForConsole, callable $getProjectDB) => $this->action($pools, $dbForConsole, $getProjectDB));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Load all documents from 'schedules' collection to create local copy
|
||||||
|
* 2. Create timer that sync all changes from 'schedules' collection to local copy. Only reading changes thanks to 'resourceUpdatedAt' attribute
|
||||||
|
* 3. Create timer that prepares coroutines for soon-to-execute schedules. When it's ready, coroutime sleeps until exact time before sending request to worker.
|
||||||
|
*/
|
||||||
|
public function action(Group $pools, Database $dbForConsole, callable $getProjectDB): void
|
||||||
|
{
|
||||||
|
Console::title('Scheduler V1');
|
||||||
|
Console::success(APP_NAME . ' Scheduler v1 has started');
|
||||||
|
|
||||||
|
$schedules = []; // Local copy of 'schedules' collection
|
||||||
|
$lastSyncUpdate = DateTime::now();
|
||||||
|
|
||||||
|
$limit = 10000;
|
||||||
|
$sum = $limit;
|
||||||
|
$total = 0;
|
||||||
|
$loadStart = \microtime(true);
|
||||||
|
$latestDocument = null;
|
||||||
|
|
||||||
|
while ($sum === $limit) {
|
||||||
|
$paginationQueries = [Query::limit($limit)];
|
||||||
|
if ($latestDocument !== null) {
|
||||||
|
$paginationQueries[] = Query::cursorAfter($latestDocument);
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
|
||||||
|
|
||||||
|
$results = $dbForConsole->find('schedules', \array_merge($paginationQueries, [
|
||||||
|
Query::lessThanEqual('schedule', DateTime::formatTz(DateTime::now())),
|
||||||
|
Query::equal('resourceType', ['message']),
|
||||||
|
Query::equal('active', [true]),
|
||||||
|
]));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
var_dump($e->getTraceAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum = count($results);
|
||||||
|
$total = $total + $sum;
|
||||||
|
foreach($results as $schedule) {
|
||||||
|
$schedules[$schedule->getId()] = $schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pools->reclaim();
|
||||||
|
|
||||||
|
Console::success("{$total} message were loaded in " . (microtime(true) - $loadStart) . " seconds");
|
||||||
|
|
||||||
|
Console::success("Starting timers at " . DateTime::now());
|
||||||
|
|
||||||
|
run(
|
||||||
|
function () use ($dbForConsole, &$schedules, &$lastSyncUpdate, $pools) {
|
||||||
|
/**
|
||||||
|
* The timer synchronize $schedules copy with database collection.
|
||||||
|
*/
|
||||||
|
Timer::tick(self::MESSAGE_UPDATE_TIMER * 1000, function () use ($dbForConsole, &$schedules, &$lastSyncUpdate, $pools) {
|
||||||
|
$time = DateTime::now();
|
||||||
|
$timerStart = \microtime(true);
|
||||||
|
|
||||||
|
$limit = 1000;
|
||||||
|
$sum = $limit;
|
||||||
|
$total = 0;
|
||||||
|
$latestDocument = null;
|
||||||
|
|
||||||
|
Console::log("Sync tick: Running at $time");
|
||||||
|
|
||||||
|
while ($sum === $limit) {
|
||||||
|
$paginationQueries = [Query::limit($limit)];
|
||||||
|
if ($latestDocument !== null) {
|
||||||
|
$paginationQueries[] = Query::cursorAfter($latestDocument);
|
||||||
|
}
|
||||||
|
$results = $dbForConsole->find('schedules', \array_merge($paginationQueries, [
|
||||||
|
Query::lessThanEqual('schedule', DateTime::formatTz(DateTime::now())),
|
||||||
|
Query::equal('resourceType', ['message']),
|
||||||
|
Query::equal('active', [true]),
|
||||||
|
]));
|
||||||
|
$sum = \count($results);
|
||||||
|
$total = $total + $sum;
|
||||||
|
foreach ($results as $schedule) {
|
||||||
|
$schedules[$schedule->getId()] = $schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestDocument = !empty(array_key_last($results)) ? $results[array_key_last($results)] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastSyncUpdate = $time;
|
||||||
|
$timerEnd = \microtime(true);
|
||||||
|
|
||||||
|
$pools->reclaim();
|
||||||
|
|
||||||
|
Console::log("Sync tick: {$total} schedules were updated in " . ($timerEnd - $timerStart) . " seconds");
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timer to prepare soon-to-execute schedules.
|
||||||
|
*/
|
||||||
|
$enqueueMessages = function () use (&$schedules, $pools, $dbForConsole) {
|
||||||
|
foreach ($schedules as $scheduleId => $schedule) {
|
||||||
|
\go(function () use ($schedules, $schedule, $pools, $dbForConsole) {
|
||||||
|
$queue = $pools->get('queue')->pop();
|
||||||
|
$connection = $queue->getResource();
|
||||||
|
$queueForMessaging = new Messaging($connection);
|
||||||
|
$queueForDeletes = new Delete($connection);
|
||||||
|
$project = $dbForConsole->getDocument('projects', $schedule->getAttribute('projectId'));
|
||||||
|
$queueForMessaging
|
||||||
|
->setMessageId($schedule->getAttribute('resourceId'))
|
||||||
|
->setProject($project)
|
||||||
|
->trigger();
|
||||||
|
$schedule->setAttribute('active', false);
|
||||||
|
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
|
||||||
|
|
||||||
|
$queueForDeletes
|
||||||
|
->setType(DELETE_TYPE_SCHEDULES)
|
||||||
|
->setDocument($schedule);
|
||||||
|
|
||||||
|
$queue->reclaim();
|
||||||
|
unset($schedules[$schedule->getId()]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Timer::tick(self::MESSAGE_ENQUEUE_TIMER * 1000, fn () => $enqueueMessages());
|
||||||
|
$enqueueMessages();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -148,7 +148,7 @@ class Deletes extends Action
|
||||||
$this->deleteCacheByDate($project, $getProjectDB, $datetime);
|
$this->deleteCacheByDate($project, $getProjectDB, $datetime);
|
||||||
break;
|
break;
|
||||||
case DELETE_TYPE_SCHEDULES:
|
case DELETE_TYPE_SCHEDULES:
|
||||||
$this->deleteSchedules($dbForConsole, $getProjectDB, $datetime);
|
$this->deleteSchedules($dbForConsole, $getProjectDB, $datetime, $document);
|
||||||
break;
|
break;
|
||||||
case DELETE_TYPE_TOPIC:
|
case DELETE_TYPE_TOPIC:
|
||||||
$this->deleteTopic($project, $getProjectDB, $document);
|
$this->deleteTopic($project, $getProjectDB, $document);
|
||||||
|
@ -167,13 +167,13 @@ class Deletes extends Action
|
||||||
* @throws Authorization
|
* @throws Authorization
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
private function deleteSchedules(Database $dbForConsole, callable $getProjectDB, string $datetime): void
|
private function deleteSchedules(Database $dbForConsole, callable $getProjectDB, string $datetime, ?Document $document = null): void
|
||||||
{
|
{
|
||||||
$this->listByGroup(
|
$this->listByGroup(
|
||||||
'schedules',
|
'schedules',
|
||||||
[
|
[
|
||||||
Query::equal('region', [App::getEnv('_APP_REGION', 'default')]),
|
Query::equal('region', [App::getEnv('_APP_REGION', 'default')]),
|
||||||
Query::equal('resourceType', ['function']),
|
Query::equal('resourceType', [$document ?? $document->getAttribute('resourceType')]),
|
||||||
Query::lessThanEqual('resourceUpdatedAt', $datetime),
|
Query::lessThanEqual('resourceUpdatedAt', $datetime),
|
||||||
Query::equal('active', [false]),
|
Query::equal('active', [false]),
|
||||||
],
|
],
|
||||||
|
|
|
@ -106,7 +106,6 @@ class Messaging extends Action
|
||||||
$targets = $dbForProject->find('targets', [Query::equal('$id', $targetsId)]);
|
$targets = $dbForProject->find('targets', [Query::equal('$id', $targetsId)]);
|
||||||
$recipients = \array_merge($recipients, $targets);
|
$recipients = \array_merge($recipients, $targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
$primaryProvider = $dbForProject->findOne('providers', [
|
$primaryProvider = $dbForProject->findOne('providers', [
|
||||||
Query::equal('enabled', [true]),
|
Query::equal('enabled', [true]),
|
||||||
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
|
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
|
||||||
|
@ -155,7 +154,6 @@ class Messaging extends Action
|
||||||
|
|
||||||
$providers[] = $provider;
|
$providers[] = $provider;
|
||||||
$identifiers = $identifiersByProviderId[$providerId];
|
$identifiers = $identifiersByProviderId[$providerId];
|
||||||
|
|
||||||
$adapter = match ($provider->getAttribute('type')) {
|
$adapter = match ($provider->getAttribute('type')) {
|
||||||
MESSAGE_TYPE_SMS => $this->sms($provider),
|
MESSAGE_TYPE_SMS => $this->sms($provider),
|
||||||
MESSAGE_TYPE_PUSH => $this->push($provider),
|
MESSAGE_TYPE_PUSH => $this->push($provider),
|
||||||
|
|
|
@ -572,7 +572,8 @@ trait MessagingBase
|
||||||
'apiKey' => $apiKey,
|
'apiKey' => $apiKey,
|
||||||
'domain' => $domain,
|
'domain' => $domain,
|
||||||
'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN),
|
'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN),
|
||||||
'from' => $from
|
'from' => $from,
|
||||||
|
'enabled' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||||
|
@ -605,18 +606,8 @@ trait MessagingBase
|
||||||
$this->assertEquals(201, $user['headers']['status-code']);
|
$this->assertEquals(201, $user['headers']['status-code']);
|
||||||
|
|
||||||
// Create Target
|
// Create Target
|
||||||
$target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [
|
$target = $user['body']['targets'][0];
|
||||||
'content-type' => 'application/json',
|
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
|
||||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
|
||||||
], [
|
|
||||||
'targetId' => ID::unique(),
|
|
||||||
'providerType' => 'email',
|
|
||||||
'providerId' => $provider['body']['$id'],
|
|
||||||
'identifier' => $to,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertEquals(201, $target['headers']['status-code']);
|
|
||||||
|
|
||||||
// Create Subscriber
|
// Create Subscriber
|
||||||
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
|
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
|
||||||
|
@ -624,7 +615,7 @@ trait MessagingBase
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
'subscriberId' => ID::unique(),
|
'subscriberId' => ID::unique(),
|
||||||
'targetId' => $target['body']['$id'],
|
'targetId' => $target['$id'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(201, $subscriber['headers']['status-code']);
|
$this->assertEquals(201, $subscriber['headers']['status-code']);
|
||||||
|
|
Loading…
Reference in a new issue