Comments (29)
Здравствуйте!
Я новичок в этом деле, прошу не закидывать камнями :)
При разработке Viber-бота на Python столкнулся с той же проблемой: повторение запросов через какое-то (случайное) время. Последовать совету Harier2008 не представляется возможным - время обработки зависит от серверов Viber и с моей стороны сократить его ни как не получается. Иногда посылка одной и той же простой клавиатуры обрабатывается 0,9 сек., иногда 25 (!!!) сек. Причем днем значительно медленней чем ночью.
Как писали авторы ранее, у одного и того же запроса, когда бы он посылался, одинаковые "message_token" и "timestamp". Решил для себя проблему так:
В самом начале бота создаю пустой список current_timestamp = [0], а дальше проверяю нет ли в нем timestamp текущего запроса. Если нет-добавляю, если есть - серверу 200
viber_request = viber.parse_request(request.get_data().decode('utf8'))
if isinstance(viber_request, ViberMessageRequest):
message_timestamp = viber_request.timestamp # Извлекается timestamp
if (current_timestamp.count(message_timestamp) != 0) : return Response(status=200) #Если этот запрос уже в списке
if (len(current_timestamp)>=30) : del current_timestamp[0] #Удаление первого, если больше 30 записей
current_timestamp.append(message_timestamp) #Добавление "timestamp" в список
Длина списка 30 взята эмпирически, с запасом. Обычно повторный запрос приходит в первой десятке и после повторного ответа серверу (2-40ms) уже не повторяется.
from viber-bot-php.
@roman7722 К сожалению работающую версию кода уже удалил, но в целом, примерно так:
use Viber\Bot;
use Viber\Api\Sender;
$botSender = new Sender([
'name' => $this->config['botName'],
'avatar' => $this->config['avatar'],
]);
$apiKey = $this->config['apiKey'];
$bot = new Bot(['token' => $apiKey]);
$bot->getClient()->sendMessage(
(new \Viber\Api\Message\Text())
->setSender($botSender)
->setReceiver(Yii::$app->request->post('user_id'))
->setText(Yii::$app->request->post('text'))
);
Туда просто отправляем post-запрос с параметрами user_id (получаем через $event->getSender()->getId()) и text (соответсвенно необходимое сообщение). Я отправлял запрос через GuzzleHttp.
from viber-bot-php.
Так это костыль
Viber это тоже сплошной костыль) Так как разработал для него крайне сложный бот, видел очень много его багов и приколов, могу с полной уверенностью сказать что продукт низкокачественный. А в целом, это единственное гарантированное решение, которое поможет с избежанием проблем повторного обрабатывания дублирующих сообщений. Бывает разное, и даже если Вашему скрипту не нужно много времени на обработку запроса, то может что-то заглючить в сети/на стороне вайбера/случится тормоза на стороне mysql/или вообще что угодно, и тогда придет дублирующий запрос. А это 100% поможет избежать любых проблем, связанной с повторной обработкой того же самого запроса.
from viber-bot-php.
Здравствуйте, данные сообщения приходят для каждого устройства (куда пришло сообщение). И у них соотвественно разные идентификаторы устройства.
from viber-bot-php.
Оказалось, что проблема была во времени ответа. У меня сервер отвечал по 6.2+ секунды, а viber при отсутствии ответа через 5 секунд уже шлет повтор на сервер. Причем львиную долю этого времени занимал запрос отправки ответа пользователю (порядка 4-5 секунд). Решил проблему тем, что вынес отправку сообщения в очереди, время отклика сократилось до 200-600 мс.
Если кто-то столкнется с проблемой, то есть быстрое решение, а именно, вынести отправку в отдельный контроллер и просто посылать на него асинхронный post запрос.
from viber-bot-php.
Уважаемый vedenskylx!
Не могли бы вы на кратеньком примере показать реализацию вашего быстрого решения, а именно как вынести отправку сообщения. Премного благодарен заранее.
from viber-bot-php.
Александр (vedenskylx), спасибо за ответ, но я спрашивал про организацию асинхронного вызова php скрипта. Как сообщение отправить это-то понятно. Но собственно мне хватило вашего пояснения, что отправляли через GuzzleHttp. Я организовал отправку вот так, (если кому поможет):
$client = new \GuzzleHttp\Client(['base_uri' => 'https://example.com/viber/mybot/']);
$promise = $client->requestAsync('POST', 'sendPicture.php', [
'form_params' => [
'receiver' => urlencode($receiver),
'answer' => urlencode($answer),
'pic' => urlencode($pic),
]
]);
$promise->wait();
а вот и сам sendPicture.php:
<?php
require_once("vendor/autoload.php");
$config = require('./config.php');
use Viber\Bot;
use Viber\Api\Sender;
$botSender = new Sender([
'name' => $config['senderName'],
'avatar' => $config['senderAvatar']
]);
$bot = new Bot(['token' => $config['apiKey']]);
$receiver = urldecode($_POST['receiver']);
$answer = urldecode($_POST['answer']);
$pic = urldecode($_POST['pic']);
$bot->getClient()->sendMessage(
(new \Viber\Api\Message\Picture())
->setSender($botSender)
->setReceiver($receiver)
->setText($answer)
->setMedia($pic)
);
Но только вот не помогло мне это (, так и приходит в Viber по несколько картинок, и с текстовыми сообщениями такая-же ситуация.
В общем пока хз что делать (
from viber-bot-php.
@roman7722 а через postman (или нечто подобное) запрос на hook сколько времени занимает?
from viber-bot-php.
vedenskylx ой, да мало, ну меньше 5 сек так точно. через 1,5-2 сек уже картинка прилетает
from viber-bot-php.
Богдан вот говорит, что для каждого устройства сообщения отправляются (второй пост сверху). Но в других-то случаях всё правильно работает, а вот в некоторых местах дублируются (и 3 и 4 раза бывает повтор)
from viber-bot-php.
и нюанс еще с асинхронностью что-то не то, пока мой sendPicture.php не выполнится, дальше основной скрипт не работает.
from viber-bot-php.
@roman7722 попробуйте таймауты добавить при отправке запроса. Если я не ошибаюсь, то так:
$promise = $client->requestAsync('POST', 'sendPicture.php', [
'form_params' => [
'receiver' => urlencode($receiver),
'answer' => urlencode($answer),
'pic' => urlencode($pic),
],
'connect_timeout' => 1,
'timeout' => 1
]);
И еще я не уверен что нужна строчка:
$promise->wait();
from viber-bot-php.
Нет Александр (vedenskylx), похоже, что асинхронность в Газл это миф.
Даже вот так, никакая асинхронность не работает:
$multicurl = new \GuzzleHttp\Handler\CurlMultiHandler();
$multihandler = \GuzzleHttp\HandlerStack::create($multicurl);
$client = new \GuzzleHttp\Client(['base_uri' => 'https://example.com/viber/mybot/', ['connect_timeout' => 3.14, 'handler' => $multihandler]]);
$promise = $client->requestAsync('POST', 'sendPicture.php', [
'form_params' => [
'receiver' => urlencode($receiver),
'answer' => urlencode($answer),
'pic' => urlencode($pic),
]
]);
$multicurl->tick();
$promise->wait();
а без $promise->wait(); вообще ничего не шлётся.
from viber-bot-php.
@roman7722 Можно попробовать чистым curl'ом баз надстроек, с прерыванием запроса. Отправка запроса вернет ошибку, но запрос отправит. Нечто вроде:
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "URL",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 1,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "DATA",
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Результат выполнения:
cURL Error #:Operation timed out after 1000 milliseconds with 0 bytes received
Status: 200 OK Time: 1151ms Size 516B
from viber-bot-php.
Александр (vedenskylx), нашёл!
Ларчик. как говорится, открывался проще :)
Сообщения дублируются, если не указывать клавиатуру, а именно:
->setKeyboard(
(new \Viber\Api\Keyboard())
->setButtons($document->getKeyset('today_yesterday_somedate'))
)
в моём случае.
from viber-bot-php.
Но идея вынести отправку в отдельный скрипт, кстати, хорошая идея ). Потом легко бота переделать под другой мессенджер, когда добрые люди решат и Viber прикрыть, как телегу ))
from viber-bot-php.
@roman7722 Все таки, мне кажется, что дело не в клавиатуре. По ощущениям, проблема на серверах viber. Периодически запросы начинают летать, ответ приходит через секунду, а иногда по 11.
З.Ы. На всякий случай обновил и протестировал скрипт чистым курлом выше, он отправляет запрос и отваливается по таймауту через секунду.
from viber-bot-php.
Ну да, сервера у них не стабильные, кстати, какие то.
А по поводу клавы хз, вродь пропала проблема, не задваиваются/затраиваются сообщения.
from viber-bot-php.
@vedenskylx Да, Александр, вы всё-таки правы, в одном месте манипуляции с клавой помогли, а в другом нет. ( Место в коде такое, что несколько сообщений нужно отправить, одно за одним, ибо не вмещается всё в одно (по мануалу 4000 символов максимально в одном сообщении можно отправлять пишут)
from viber-bot-php.
Исправил и во втором месте бота, где задваивались месседжи, установил предел размера текста в 2000 символов, теперь нормально шлются, без повторов.
Осталось побороть момент, где несколько картинок нужно отправить, тоже дубляж идёт. вместо 2-3х картинок отправляется 4-6. Пока решения нет.
from viber-bot-php.
Столкнулся с этой проблемой, и самостоятельно с ней разобрался. Дублирование происходит со стороны Viber, если не ответить на сообщение на протяжении 5 секунд. Т.е. ставим sleep(4) - все работает (и в Viber-е светится что сообщение доставлено), если sleep 5 (или чуть дольше) - даже если сервер принял/обработал сообщение/отправил ответ - Viber-у все равно , он в любом случае пришлет дубль через некоторое время (и в чате уже не светится что сообщение доставлено). Я изучил весь их алгоритм, но, к сожалению, так как это было примерно 2 месяца назад, уже подзабыл. Примерно (говорю по памяти, могут быть неточности), алгоритм такой:
- Если сервер получил сообщение и обрабатывает его больше 5 секунд - дублирование будет 100%. НО, сделает это viber в тот момент (вроде через секунду), как сервер даст ответ. Например: пришло сообщение на сервер, скрипт отвечает/молчит/... 65сек, в тот момент когда завершиться работа скрипта (и Viber увидит что сервер закончил работу) - происходит повторная отправка сообщения (и ему абсолютно все равно чем закончился предыдущий запрос)
- Такое, происходит примерно 3 раза. После этих нескольких раз, Viber уже делает паузу перед посылом следующего дубля - 1 минуту. Далее тот же алгоритм, он ожидает пока не ответит сервер (не помню сколько, но ожидает достаточно долго, вроде около минуты), и после этого берет паузу опять на 1 минуту. Если и следующий раз сервер не ответил вовремя - Viber перестает слать уведомления.
Схема примерно следующая (повторюсь, могут быть неточности, так как уже всего не помню), это при условии если КАЖДЫЙ запрос происходит более чем 5 сек:
Запрос на сервер/долгое ожидание ответа->после того как сервер закончил, повторный запрос сразу.
Так вроде 3 раза.
Потом пауза на 1 мин. Потом опять запрос на сервер/долгое ожидание ответа->после того как сервер закончил, повторный запрос через 1 минуту.
На этом все.
В общем, примерно как-то так, думаю общий принцип понятен.
Еще, вроде как, у Viber-а есть очередь сообщений. Если скрипт не обработает первое сообщение от пользователя (т.е. либо пока не ответит меньше чем за 5сек, или же пока Viber не сделает все свои попытки уведомить сервер), то второе он не получит.
Ну и опытным путем еще какие-то баги были (по моему, если за каким-то разом сообщение таки обработать вовремя, Viber этого не видит, и все равно "спамит"), или что-то в этом роде.
Поскольку для меня проблема с дублированием была критичной, то решил я его примерно так:
->on(function(Event $event){
$token = (int)$event->getMessageToken();
$message = $this->db->getRow("SELECT * FROM `duplicate_messages` WHERE `message_token`='{$token}'");
if(isset($message)){
//var_dump('delete duplicate message');
exit;
}
$this->db->insert('duplicate_messages', ['message_token'=>$token, 'created_time'=>time()]);
return false;
}, function (){})
->on(function(Event $event){
//остальные обработчики
ну и чистку бд по крону:
$db->query("DELETE FROM `duplicate_messages` WHERE `created_time`<".(time()-MIN*10));
Если что не понятно - спрашивайте, отвечу/объясню.
from viber-bot-php.
48769e2c5067d493-f8c18d0c809d0d95-b23d553fa6244d4f
from viber-bot-php.
48769e2c5067d493-f8c18d0c809d0d95-b23d553fa6244d4f
from viber-bot-php.
fooger, красавчик!
from viber-bot-php.
Столкнулся с этой проблемой, и самостоятельно с ней разобрался.
Исследование отличное! Спасибо.
Решение тоже интересное, но решив проблему с дублированием - останется проблема с тем, что сообщение будет отображаться как не доставленное. Да и постоянный спам от серверов viber на сервер тоже не очень хорошо.
Я решил проблему иначе. Тоже скорее всего костыль, но работает :)
Мне нужно было по запросам от клиента получать данные из базы и отправлять ему ответ.
Собственно как раз время на получение данных превышало эти злополучные 5 секунд, поэтому я просто в onText получал Viber ID (getSender()->getId()) отправителя и текст (getMessage()->getText()) и эти данные отправлял при помощи чистого CURL на url отдельного скрипта, который уже выполнял всю работу с БД, а дальше после выполнения запроса в БД выполнял sendMessage c этими данными на полученный Viber ID.
from viber-bot-php.
Данная проблема по прежнему актуальна, есть у кого-нибудь нормальное решение?
from viber-bot-php.
Ну смотрите. Скрипт, который вы пищите, выполняется каждый раз, когда на ваш сервер приходит сообщение. В случае, если за 5 секунд сообщение не прошло, повторяется дублирование. Про это уже выше писали.
У всех этих повторяющихся сообщений один и тот же идентификатор. я его получаю так:
$token = (int)$event->getMessageToken();
Дальше у меня есть отдельная таблица в БД для контроля дублирования сообщений. Я проверяю, есть ли у меня запись о получении этого сообщения. Если нет, то я добавляю эту запись. если есть - прерываю скрипт.
$token_control = mysql_num_rows(mysql_query("SELECT 1 FROM `duplicate_messages` WHERE message_id = '$token'"));
$date_msg=date("Y-m-d H:i:s");
IF( $token_control == 0 )
{
mysql_query("INSERT INTO `duplicate_messages` (user_id, message_id, message_time) VALUES ('$receiverId', '$token', '$date_msg')");
}
ELSE
{
exit;
}
Чтобы не хранить информацию о сообщениях, которая не актуальна, делаю так:
$time_left = date("Y/m/d H:i:s", mktime(date("H"), date("i")-10, date("s"), date("m") , date("d"), date("Y")));
mysql_query("DELETE FROM duplicate_messages WHERE message_time < '$time_left'");
и все это обрабатывается внутри ->onText, которая у меня одна на весь скрипт. Я беру из нее текст, присланный пользователем и уже внутри обрабатываю, как мне надо.
$onText_buffer = $event->getMessage()->getText();
from viber-bot-php.
Ну смотрите. Скрипт, который вы пищите, выполняется каждый раз, когда на ваш сервер приходит сообщение. В случае, если за 5 секунд сообщение не прошло, повторяется дублирование. Про это уже выше писали.
У всех этих повторяющихся сообщений один и тот же идентификатор. я его получаю так:
$token = (int)$event->getMessageToken();Дальше у меня есть отдельная таблица в БД для контроля дублирования сообщений. Я проверяю, есть ли у меня запись о получении этого сообщения. Если нет, то я добавляю эту запись. если есть - прерываю скрипт.
$token_control = mysql_num_rows(mysql_query("SELECT 1 FROM `duplicate_messages` WHERE message_id = '$token'")); $date_msg=date("Y-m-d H:i:s"); IF( $token_control == 0 ) { mysql_query("INSERT INTO `duplicate_messages` (user_id, message_id, message_time) VALUES ('$receiverId', '$token', '$date_msg')"); } ELSE { exit; }Чтобы не хранить информацию о сообщениях, которая не актуальна, делаю так:
$time_left = date("Y/m/d H:i:s", mktime(date("H"), date("i")-10, date("s"), date("m") , date("d"), date("Y"))); mysql_query("DELETE FROM duplicate_messages WHERE message_time < '$time_left'");и все это обрабатывается внутри ->onText, которая у меня одна на весь скрипт. Я беру из нее текст, присланный пользователем и уже внутри обрабатываю, как мне надо.
$onText_buffer = $event->getMessage()->getText();
Так это костыль
from viber-bot-php.
Делайте так чтобы ответ на сервера вайбер гарантированно был отдан менее чем за 5 секунд и никаких костылей не потребуется.
from viber-bot-php.
Related Issues (20)
- Отправка сообщений на почту
- Обновление зависимостей HOT 6
- Uncaught exception 'RuntimeException' with message 'Signature header not found'
- При нажатии на кнопку ее текст выводиться в чате HOT 1
- onConversation() dont send welcome message. HOT 1
- How to send one message to several people?
- Не работает setInputFieldState HOT 2
- Как добавить значение из массива в кнопки для вайбер бота HOT 1
- viber
- Как обрабатывать нажатие на кнопки?
- Misspelled Failure event classsproperty dsc
- Как отправить сразу несколько изображений!??
- Ссылка на телефон в сообщении
- [Viber Bug] Web hook URL query parameters
- Подскажите как отследить отписку? HOT 4
- There is a problem with return types while extending Bot class
- Перенос бота HOT 1
- Не подключает файлы autoload
- Как удалить старый вебхук
- java.util.concurrent.TimeoutException
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from viber-bot-php.