PurgeCache.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\CacheInvalidate\Model;
  7. use Magento\Framework\Cache\InvalidateLogger;
  8. /**
  9. * Class PurgeCache
  10. */
  11. class PurgeCache
  12. {
  13. const HEADER_X_MAGENTO_TAGS_PATTERN = 'X-Magento-Tags-Pattern';
  14. /**
  15. * @var \Magento\PageCache\Model\Cache\Server
  16. */
  17. protected $cacheServer;
  18. /**
  19. * @var \Magento\CacheInvalidate\Model\SocketFactory
  20. */
  21. protected $socketAdapterFactory;
  22. /**
  23. * @var InvalidateLogger
  24. */
  25. private $logger;
  26. /**
  27. * Batch size of the purge request.
  28. *
  29. * Based on default Varnish 4 http_req_hdr_len size minus a 512 bytes margin for method,
  30. * header name, line feeds etc.
  31. *
  32. * @see https://varnish-cache.org/docs/4.1/reference/varnishd.html
  33. *
  34. * @var int
  35. */
  36. private $requestSize = 7680;
  37. /**
  38. * Constructor
  39. *
  40. * @param \Magento\PageCache\Model\Cache\Server $cacheServer
  41. * @param \Magento\CacheInvalidate\Model\SocketFactory $socketAdapterFactory
  42. * @param InvalidateLogger $logger
  43. */
  44. public function __construct(
  45. \Magento\PageCache\Model\Cache\Server $cacheServer,
  46. \Magento\CacheInvalidate\Model\SocketFactory $socketAdapterFactory,
  47. InvalidateLogger $logger
  48. ) {
  49. $this->cacheServer = $cacheServer;
  50. $this->socketAdapterFactory = $socketAdapterFactory;
  51. $this->logger = $logger;
  52. }
  53. /**
  54. * Send curl purge request to invalidate cache by tags pattern
  55. *
  56. * @param string $tagsPattern
  57. * @return bool Return true if successful; otherwise return false
  58. */
  59. public function sendPurgeRequest($tagsPattern)
  60. {
  61. $successful = true;
  62. $socketAdapter = $this->socketAdapterFactory->create();
  63. $servers = $this->cacheServer->getUris();
  64. $socketAdapter->setOptions(['timeout' => 10]);
  65. $formattedTagsChunks = $this->splitTags($tagsPattern);
  66. foreach ($formattedTagsChunks as $formattedTagsChunk) {
  67. if (!$this->sendPurgeRequestToServers($socketAdapter, $servers, $formattedTagsChunk)) {
  68. $successful = false;
  69. }
  70. }
  71. return $successful;
  72. }
  73. /**
  74. * Split tags by batches
  75. *
  76. * @param string $tagsPattern
  77. * @return \Generator
  78. */
  79. private function splitTags($tagsPattern)
  80. {
  81. $tagsBatchSize = 0;
  82. $formattedTagsChunk = [];
  83. $formattedTags = explode('|', $tagsPattern);
  84. foreach ($formattedTags as $formattedTag) {
  85. if ($tagsBatchSize + strlen($formattedTag) > $this->requestSize - count($formattedTagsChunk) - 1) {
  86. yield implode('|', $formattedTagsChunk);
  87. $formattedTagsChunk = [];
  88. $tagsBatchSize = 0;
  89. }
  90. $tagsBatchSize += strlen($formattedTag);
  91. $formattedTagsChunk[] = $formattedTag;
  92. }
  93. if (!empty($formattedTagsChunk)) {
  94. yield implode('|', $formattedTagsChunk);
  95. }
  96. }
  97. /**
  98. * Send curl purge request to servers to invalidate cache by tags pattern
  99. *
  100. * @param \Zend\Http\Client\Adapter\Socket $socketAdapter
  101. * @param \Zend\Uri\Uri[] $servers
  102. * @param string $formattedTagsChunk
  103. * @return bool Return true if successful; otherwise return false
  104. */
  105. private function sendPurgeRequestToServers($socketAdapter, $servers, $formattedTagsChunk)
  106. {
  107. $headers = [self::HEADER_X_MAGENTO_TAGS_PATTERN => $formattedTagsChunk];
  108. foreach ($servers as $server) {
  109. $headers['Host'] = $server->getHost();
  110. try {
  111. $socketAdapter->connect($server->getHost(), $server->getPort());
  112. $socketAdapter->write(
  113. 'PURGE',
  114. $server,
  115. '1.1',
  116. $headers
  117. );
  118. $socketAdapter->read();
  119. $socketAdapter->close();
  120. } catch (\Exception $e) {
  121. $this->logger->critical($e->getMessage(), compact('server', 'formattedTagsChunk'));
  122. return false;
  123. }
  124. }
  125. $this->logger->execute(compact('servers', 'formattedTagsChunk'));
  126. return true;
  127. }
  128. }