Files
kiri-core/Kafka/Producer.php
T

191 lines
4.0 KiB
PHP
Raw Normal View History

2020-10-09 10:58:37 +08:00
<?php
2020-10-29 18:17:25 +08:00
declare(strict_types=1);
2020-10-09 10:58:37 +08:00
namespace Kafka;
2020-10-30 11:35:17 +08:00
use Exception;
2020-10-28 15:47:39 +08:00
use RdKafka\Conf;
2021-02-14 21:29:59 +08:00
use RdKafka\ProducerTopic;
2020-10-28 15:47:39 +08:00
use RdKafka\TopicConf;
2020-10-28 16:01:36 +08:00
use ReflectionException;
2020-10-28 15:47:39 +08:00
use Snowflake\Abstracts\Component;
2021-03-24 17:20:32 +08:00
use Snowflake\Abstracts\Config;
2020-10-28 16:24:55 +08:00
use Snowflake\Event;
2020-10-28 16:01:36 +08:00
use Snowflake\Exception\NotFindClassException;
use Snowflake\Snowflake;
2020-10-09 10:58:37 +08:00
2020-10-28 15:47:39 +08:00
/**
* +------------------------------------------------------------------------------
* Kafka protocol since Kafka v0.8
* +------------------------------------------------------------------------------
*
* @package
* @version $_SWANBR_VERSION_$
* @copyright Copyleft
* @author $_SWANBR_AUTHOR_$
* +------------------------------------------------------------------------------
*/
class Producer extends Component
2020-10-09 10:58:37 +08:00
{
2020-10-28 16:01:36 +08:00
private string $_topic = '';
2020-10-28 16:04:52 +08:00
private Conf $conf;
private TopicConf $topicConf;
2020-10-30 11:25:14 +08:00
private ?\RdKafka\Producer $producer = null;
2020-10-30 11:22:37 +08:00
2020-10-28 16:04:52 +08:00
2021-03-24 17:20:32 +08:00
/**
* Producer constructor.
* @param array $config
*/
2020-10-28 16:11:19 +08:00
public function __construct($config = [])
{
2020-10-28 17:50:48 +08:00
parent::__construct($config);
if (!class_exists(Conf::class)) {
return;
}
2020-10-28 16:12:30 +08:00
$this->conf = new Conf();
$this->topicConf = new TopicConf();
2020-10-28 16:11:19 +08:00
}
2020-10-28 16:01:36 +08:00
/**
* @param $servers
* @return Producer
*/
2020-12-17 14:09:14 +08:00
public function setBrokers(string $servers): static
2020-10-28 16:01:36 +08:00
{
2020-10-28 16:04:52 +08:00
$this->conf->set('metadata.broker.list', $servers);
2020-10-28 16:01:36 +08:00
return $this;
}
2021-03-18 16:37:47 +08:00
/**
* @param string $groupId
* @return Producer
*/
public function setGroupId(string $groupId): static
{
$this->conf->set('group.id', $groupId);
return $this;
}
2020-10-28 16:01:36 +08:00
/**
* @param $servers
* @return Producer
*/
2020-12-17 14:09:14 +08:00
public function setTopic(string $servers): static
2020-10-28 16:01:36 +08:00
{
$this->_topic = $servers;
return $this;
}
2021-03-24 17:20:32 +08:00
/**
* @param string $topic
* @param array $params
* @param string|null $groupId
2021-03-24 19:23:09 +08:00
* @throws Exception
2021-03-24 17:20:32 +08:00
*/
public function dispatch(string $topic, array $params = [], string $groupId = null)
{
2021-03-24 19:21:02 +08:00
$consumers = Config::get('kafka.consumers.' . $topic);
if (empty($consumers) || !is_array($consumers)) {
return;
}
2021-03-24 19:23:09 +08:00
if (!isset($consumers['brokers'])) {
throw new Exception('You need set brokers config.');
}
2021-03-24 19:21:02 +08:00
if (!empty($groupId)) {
$consumers['groupId'] = $groupId;
} else if (!isset($consumers['groupId'])) {
$consumers['groupId'] = $topic . ':' . Snowflake::localhost();
2021-03-24 17:20:32 +08:00
}
2021-03-24 19:41:21 +08:00
$this->setGroupId($consumers['groupId'])->setTopic($topic)
2021-03-24 19:23:09 +08:00
->setBrokers($consumers['brokers'])
2021-03-24 19:21:02 +08:00
->delivery(swoole_serialize($params));
2021-03-24 17:20:32 +08:00
}
2020-10-28 15:47:39 +08:00
/**
* @param $message
* @param null $key
2020-10-30 11:33:37 +08:00
* @param bool $isAck
* @throws NotFindClassException
* @throws ReflectionException
2020-10-30 11:35:17 +08:00
* @throws Exception
2020-10-28 15:47:39 +08:00
*/
2020-10-30 11:33:37 +08:00
public function delivery($message, $key = null, $isAck = false)
2020-10-28 15:47:39 +08:00
{
2020-10-28 16:04:52 +08:00
if (!$this->conf || !$this->topicConf) {
2020-10-30 11:35:17 +08:00
throw new Exception('Error. Please set kafka conf.');
2020-10-28 16:04:52 +08:00
}
$this->conf->setErrorCb(function ($kafka, $err, $reason) {
2020-10-28 15:47:39 +08:00
$this->error(sprintf("Kafka error: %s (reason: %s)", rd_kafka_err2str($err), $reason));
});
2020-10-30 11:22:37 +08:00
$event = Snowflake::app()->getEvent();
2021-02-20 15:21:42 +08:00
$event->on(Event::SYSTEM_RESOURCE_RELEASES, [$this, 'flush']);
2020-10-30 11:22:37 +08:00
2020-10-30 11:25:14 +08:00
if ($this->producer === null) {
2020-10-30 11:24:22 +08:00
$this->producer = Snowflake::createObject(\RdKafka\Producer::class, [$this->conf]);
}
2020-10-30 11:33:37 +08:00
2020-10-30 11:35:17 +08:00
$this->setTopicAcks($isAck);
$this->push($message, $key);
2020-10-30 11:54:29 +08:00
if ($isAck === true) {
2020-10-30 11:54:07 +08:00
$this->flush();
}
2020-10-30 11:35:17 +08:00
}
2021-03-24 17:20:32 +08:00
/** @var ProducerTopic[] $topics */
2021-02-14 21:29:59 +08:00
private array $topics = [];
/**
* @param $message
* @param $key
*/
2020-10-30 11:35:17 +08:00
private function push($message, $key)
{
2021-03-24 17:20:32 +08:00
if (!isset($this->topics[$this->_topic])) {
2021-02-14 21:29:59 +08:00
$this->topics[$this->_topic] = $this->producer->newTopic($this->_topic, $this->topicConf);
}
$this->topics[$this->_topic]->produce(RD_KAFKA_PARTITION_UA, 0, $message, $key);
2020-10-30 11:35:17 +08:00
$this->producer->poll(0);
}
/**
* @param $isAck
*/
private function setTopicAcks(bool $isAck)
{
2020-10-30 11:33:37 +08:00
if ($isAck) {
2020-10-30 11:35:17 +08:00
if ($this->producer->getOutQLen() > 0) {
2020-10-30 11:33:37 +08:00
$this->flush();
}
$this->topicConf->set('request.required.acks', '1');
} else {
$this->topicConf->set('request.required.acks', '0');
}
2020-10-28 16:48:10 +08:00
}
2020-10-30 11:35:17 +08:00
2020-10-30 11:22:37 +08:00
public function flush()
2020-10-28 16:48:10 +08:00
{
2020-10-30 11:22:37 +08:00
while ($this->producer->getOutQLen() > 0) {
$result = $this->producer->flush(100);
if (RD_KAFKA_RESP_ERR_NO_ERROR === $result) {
break;
}
2020-10-28 16:49:44 +08:00
}
2020-10-28 15:47:39 +08:00
}
2020-10-28 16:48:10 +08:00
2020-10-09 10:58:37 +08:00
}