-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5923d08
commit a03d361
Showing
5 changed files
with
238 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
|
||
namespace Frosh\SentryBundle\DependencyInjection; | ||
|
||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | ||
use Symfony\Component\Config\Definition\ConfigurationInterface; | ||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | ||
|
||
class Configuration implements ConfigurationInterface | ||
{ | ||
public function getConfigTreeBuilder() | ||
{ | ||
$treeBuilder = new TreeBuilder('frosh_sentry'); | ||
$rootNode = $treeBuilder->getRootNode(); | ||
|
||
$rootNode | ||
->children() | ||
->booleanNode('report_scheduled_tasks')->defaultFalse()->end() | ||
->end(); | ||
|
||
return $treeBuilder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Frosh\SentryBundle\DependencyInjection; | ||
|
||
use Symfony\Component\Config\Definition\ConfigurationInterface; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Extension\Extension; | ||
|
||
class FroshSentryExtension extends Extension | ||
{ | ||
/** | ||
* @param array<mixed> $configs | ||
*/ | ||
public function load(array $configs, ContainerBuilder $container): void | ||
{ | ||
$config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs); | ||
$this->addConfig($container, $this->getAlias(), $config); | ||
} | ||
|
||
/** | ||
* @param array<mixed> $config | ||
*/ | ||
public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface | ||
{ | ||
return new Configuration(); | ||
} | ||
|
||
/** | ||
* @param array<array<string>|bool|float|int|string|null> $options | ||
*/ | ||
private function addConfig(ContainerBuilder $container, string $alias, array $options): void | ||
{ | ||
foreach ($options as $key => $option) { | ||
$container->setParameter($alias . '.' . $key, $option); | ||
|
||
if (\is_array($option)) { | ||
$this->addConfig($container, $alias . '.' . $key, $option); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Frosh\SentryBundle\Subscriber; | ||
|
||
use MbCore\Component\Gallery\Entity\GalleryDefinition; | ||
use Sentry\MonitorConfig; | ||
use Sentry\MonitorScheduleUnit; | ||
use Shopware\Core\Framework\Api\Context\SystemSource; | ||
use Shopware\Core\Framework\Context; | ||
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\ChangeSet; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\ChangeSetAware; | ||
use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent; | ||
use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskCollection; | ||
use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskDefinition; | ||
use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskEntity; | ||
use Shopware\Core\Framework\Struct\ArrayStruct; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Sentry\CheckInStatus; | ||
use Sentry\MonitorSchedule; | ||
use function Sentry\captureCheckIn; | ||
|
||
class ScheduledTaskSubscriber implements EventSubscriberInterface | ||
{ | ||
private ?ScheduledTaskCollection $scheduledTaskCollection = null; | ||
|
||
/** | ||
* @param EntityRepository<ScheduledTaskCollection> $scheduledTaskRepository | ||
*/ | ||
public function __construct( | ||
private readonly EntityRepository $scheduledTaskRepository, | ||
private readonly bool $reportScheduledTasks | ||
) | ||
{ | ||
} | ||
|
||
public static function getSubscribedEvents(): array | ||
{ | ||
return [ | ||
PreWriteValidationEvent::class => 'triggerChangeSet', | ||
'scheduled_task.written' => 'onScheduledTaskWritten', | ||
]; | ||
} | ||
|
||
public function triggerChangeSet(PreWriteValidationEvent $event): void | ||
{ | ||
if (!$this->reportScheduledTasks) { | ||
return; | ||
} | ||
|
||
foreach ($event->getCommands() as $command) { | ||
if (!$command instanceof ChangeSetAware) { | ||
continue; | ||
} | ||
|
||
if ($command->getEntityName() !== ScheduledTaskDefinition::ENTITY_NAME) { | ||
continue; | ||
} | ||
|
||
$command->requestChangeSet(); | ||
} | ||
} | ||
|
||
public function onScheduledTaskWritten(EntityWrittenEvent $event): void | ||
{ | ||
if (!$this->reportScheduledTasks) { | ||
return; | ||
} | ||
|
||
$this->fetchScheduledTaskCollection(); | ||
|
||
foreach ($event->getWriteResults() as $writeResult) { | ||
$scheduledTaskId = $writeResult->getPrimaryKey(); | ||
if (!\is_string($scheduledTaskId)) { | ||
continue; | ||
} | ||
|
||
$scheduledTask = $this->scheduledTaskCollection?->get($scheduledTaskId); | ||
if (!$scheduledTask instanceof ScheduledTaskEntity) { | ||
continue; | ||
} | ||
|
||
$changeSet = $writeResult->getChangeSet(); | ||
if (!$changeSet instanceof ChangeSet) { | ||
continue; | ||
} | ||
|
||
$checkInStatus = match ($changeSet->getAfter('status')) { | ||
ScheduledTaskDefinition::STATUS_RUNNING => CheckInStatus::inProgress(), | ||
ScheduledTaskDefinition::STATUS_SCHEDULED => CheckInStatus::ok(), | ||
ScheduledTaskDefinition::STATUS_FAILED => CheckInStatus::error(), | ||
default => null | ||
}; | ||
|
||
if ($checkInStatus !== null) { | ||
$this->captureCheckIn($scheduledTask, $checkInStatus); | ||
} | ||
} | ||
} | ||
|
||
private function captureCheckIn(ScheduledTaskEntity $scheduledTask, CheckInStatus $status): void | ||
{ | ||
if($status === CheckInStatus::inProgress()) { | ||
$scheduledTask->removeExtension('sentryCheckInId'); | ||
$checkInId = $this->getCheckInId($scheduledTask); | ||
$scheduledTask->addArrayExtension('sentryCheckInId', [$checkInId]); | ||
} else { | ||
$checkInId = $this->getCheckInId($scheduledTask); | ||
captureCheckIn(slug: $scheduledTask->getName(), status: $status, checkInId: $checkInId); | ||
} | ||
} | ||
|
||
private function getCheckInId(ScheduledTaskEntity $scheduledTask): ?string | ||
{ | ||
$extension = $scheduledTask->getExtension('sentryCheckInId'); | ||
if($extension instanceof ArrayStruct) { | ||
return \is_string($extension->get(0)) ? $extension->get(0) : null; | ||
} | ||
|
||
return captureCheckIn( | ||
slug: $scheduledTask->getName(), | ||
status: CheckInStatus::inProgress(), | ||
monitorConfig: $this->monitorConfig($scheduledTask) | ||
); | ||
} | ||
|
||
private function monitorConfig(ScheduledTaskEntity $scheduledTask): MonitorConfig | ||
{ | ||
$interval = max(1, (int) ($scheduledTask->getRunInterval() / 60)); | ||
$monitorSchedule = MonitorSchedule::interval($interval, MonitorScheduleUnit::minute()); | ||
|
||
return new MonitorConfig($monitorSchedule); | ||
} | ||
|
||
private function fetchScheduledTaskCollection(): void | ||
{ | ||
if ($this->scheduledTaskCollection instanceof ScheduledTaskCollection) { | ||
return; | ||
} | ||
|
||
$context = new Context(new SystemSource()); | ||
$criteria = new Criteria(); | ||
|
||
$this->scheduledTaskCollection = $this->scheduledTaskRepository->search($criteria, $context)->getEntities(); | ||
} | ||
} |