Telethon - Many messages have views=None - telethon

I'm trying to get the messages's views count through Telethon.
async def get_messages(entity=None, post_id=None, limit=1):
await app.tl_client.get_dialogs()
input_entity = await app.tl_client.get_input_entity(entity)
print('input_entity->', input_entity)
message = await app.tl_client.get_messages(entity, ids=post_id, limit=limit)
print('message ->', message)
The output is a Message object having views=None.
This happens for some messages, not all. How can a message have None views ? Is it a setting for chat administrators ?

Only messages in broadcast channels, or messages forwarded from them, have views. Notably, this means messages from private conversations, small group chats, and megagroup channels ("supergroups") will have views = None unless it is forwarded from a broadcast channel.

Related

ServiceStack RedisMqServer: No way to add or remove channels in runtime?

My, already "legacy" by now, implementation of a pub/sub solution using ServiceStack quickly ran out of clients, when it reached the 20 client limit.
We do something like:
_redisConsumer = MqClientFactory.Instance.GetRedisClient(); // Returns a IRedisClient
_subscription = _redisConsumer.CreateSubscription();
_subscription.OnSubscribe = channel => CoreLog.Instance.Info($"Subscription started on {eventChannelName}");
_subscription.OnUnSubscribe = channel => CoreLog.Instance.Warning($"Unsubscribed from {eventChannelName}");
_subscription.OnMessage = (channel, msg) =>
{
try
{
onMessageReceived(CoreRequestJsonEnvelope.CreateCoreRequestFromJson(msg));
}
catch (Exception ex)
{
CoreLog.Instance.Exception(ex);
}
};
// Since it blocks execution, we put this in a Task:
Task.Run(() =>
{
try
{
_subscription.SubscribeToChannels(eventChannelName); // blocking
}
catch(Exception e)
{
}
});
and when we have enough different channels to listen too, it runs out.
I then thought, that maybe instead of taking a new IRedisClient for each subscription, I could use the same IRedisClient for all of them, so:
_redisConsumer = mySavedRedisClient;
...
but that returns Unknown reply on multi-request after a few seconds/executions.
Lastly, I looked at the RedisPubSubServer, but it seems that I need to specify the channels in the constructor, and I cannot change after that. I do need to add and remove channels in runtime, and channels are not known from start.
What is the recommended approach?
Is it to increaase the Max-limit and continue as before?
Is it to use RedisPubSub, but how to handle dynamic channels?
What does "unknown reply on multi-request" actually mean?
Thanks!
It's not clear what 20 client limit you're referring to & how the client limit is dependent on channels or subscribers, but if this is your App own limit than sounds like increasing it would be the easiest solution.
ServiceStack.Redis doesn't support changing the subscribed channels after a subscription has started. Instead of managing the IRedisSubscription yourself you may want to consider ServiceStack.Redis Managed Pub/Sub Server which manages the background subscription thread with added resiliency and support for auto retries.
Whilst you can't change the subscribed channels at runtime, you can modify the modify the Channels collection and restart the subscription to create a new subscription to the updated channels list, e.g:
var pubSub = new RedisPubSubServer(clientsManager, chan1);
pubSub.Start();
//...
pubSub.Channels = new[] { chan1, chan2 };
pubSub.Restart();
Otherwise depending on your use-case you may be able to subscribe to a channel pattern which allows you to subscribe to a multiple dynamic channels matching wildcard channel pattern:
var pubSub = new RedisPubSubServer(clientsManager) {
ChannelsMatching = new[] { "chan:*" }
}
.Start();
Where it will handle any messages clients send that matches the channel pattern.

Getting failure callback for Producer in rabbitmq when back pressure kicks in

I wanted to find out the failed messages for my rabbitmq producers using some call back api.I have configured rabbitmq with [{rabbit, [{vm_memory_high_watermark, 0.001}]}]. and tried pushing lot of messages but all the messages are getting accepted and TimeoutException is coming later on and messages not getting send to Queueenter code here, Please tell me how to capture it.
Code for sending message:
// #create-sink - producer
final Sink<ByteString, CompletionStage<Done>> amqpSink =
AmqpSink.createSimple(
AmqpSinkSettings.create(connectionProvider)
.withRoutingKey(AkkaConstants.queueName)
.withDeclaration(queueDeclaration));
// #run-sink
//final List<String> input = Arrays.asList("one", "two", "three", "four", "five");
//Source.from(input).map(ByteString::fromString).runWith(amqpSink, materializer);
String filePath = "D:\\subrata\\code\\akkaAmqpTest-master\\akkaAmqpTest-master\\logs2\\dummy.txt";
Path path = Paths.get(filePath);
// List containing 78198 individual message
List<String> contents = Files.readAllLines(path);
System.out.println("********** file reading done ....");
int times = 5;
// Send 78198*times message to Queue [From console i can see 400000 number of messages being sent]
for(int i=0;i<times;i++) {
Source.from(contents).map(ByteString::fromString).runWith(amqpSink, materializer);
}
System.out.println("************* sending to queue is done");
Unfortunately currently that is not supported out of the box. Ideally the producer would be modeled as a Flow which would send all incoming messages to the AMQP broker and would emit the same message with a result weather it has been successfully sent to the broker or not. There is a ticket to track this possible improvement on the Alpakka issue tracker.

How do I get old messages from RabbitMQ?

I'm publishing RabbitMQ messages using Bunny (Ruby) like this:
x.publish("Message !"+n.to_s, :routing_key => 'mychannel')
and subscribing like this:
ch = conn.create_channel
x = ch.topic('fling',durable: true)
q = ch.queue("")
q.bind(x, :routing_key => 'mychannel')
puts "Waiting for messages."
q.subscribe( :block => true) do |delivery_info, properties, body|
puts " [x] Received #{body}, message properties are #{properties.inspect}"
Once I start the subscriber, it immediately receives any messages which are sent. However, if I send messages without starting the subscriber, they aren't received when I start the subscriber (whether the sender is still pushing messages, or not).
Is it possible to go back through the queue and receive messages that were sent in the past, when no subscribers were listening?
You're making a new queue each time you start the consumer! So when you restart the consumer, the new queue gets new messages, but doesn't have previous ones.
Do this:
q = ch.queue("myqueue",durable: true)
instead of this:
q = ch.queue("")
Then, as soon as you restart the consumer, it will immediately get all backed-up messages as fast as it can.
Queue has to be parameter called durable its never losses
ch.queue(queue, {
durable: true
});
instead
q = ch.queue("")

Rabbitmq: different between envelop.message.body and envelop.message.pool

I have one producer based on nodejs and the javascript library which I used is amqp.node, and the consumer is implemented by C library.
From rabbitmq management web, I can see the messages are pushed into the queue and delivered to the consumer. In the consumer, the amqp_consume_message return AMQP-RESPONSE-NORMAL, however, the envelop.message.body is null. How can I debug it in this case?
Here are my codes to consume messages from rabbitmq
amqp_rpc_reply_t reply;
amqp_envelope_t envelope;
amqp_maybe_release_buffers(m_con);
timeval m_time;
m_time.tv_sec = dwMilliseconds/1000;
m_time.tv_usec = (dwMilliseconds%1000)*1000;
reply = amqp_consume_message(m_con, &envelope, &m_time, 0);//time out 1 second
if (AMQP_RESPONSE_NORMAL != reply.reply_type)
{
return false;
}
bool bRet = false;
amqp_bytes_t& rTheBody = envelope.message.body;
if (rTheBody.len > 0)
{
Update
After further investigation, I find those messages are stored in the envelop.message.pool.pages. I want to the different between message.body and message.pool?
Quoting this
The pool field of the amqp_message_t object (e.g.,
envelope.message.pool) is a memory pool used for allocating parts of
the message. It is an implementation detail and should not be used by
client code directly (this implementation detail is subject to
change).
The only reason that the envelope.message.body.bytes should be NULL
with a AMQP_RESPONSE_NORMAL return value is if a 0-length message body
is received.

Rabbitmq retrieve multiple messages using single synchronous call

Is there a way to receive multiple message using a single synchronous call ?
When I know that there are N messages( N could be a small value less than 10) in the queue, then I should be able to do something like channel.basic_get(String queue, boolean autoAck , int numberofMsg ). I don't want to make multiple requests to the server .
RabbitMQ's basic.get doesn't support multiple messages unfortunately as seen in the docs. The preferred method to retrieve multiple messages is to use basic.consume which will push the messages to the client avoiding multiple round trips. acks are asynchronous so your client won't be waiting for the server to respond. basic.consume also has the benefit of allowing RabbitMQ to redeliver the message if the client disconnects, something that basic.get cannot do. This can be turned off as well setting no-ack to true.
Setting basic.qos prefetch-count will set the number of messages to push to the client at any time. If there isn't a message waiting on the client side (which would return immediately) client libraries tend to block with an optional timeout.
You can use a QueueingConsumer implementation of Consumer interface which allows you to retrieve several messages in a single request.
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
channel.basicConsume(plugin.getQueueName(), false, queueingConsumer);
for(int i = 0; i < 10; i++){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(100);//read timeout in ms
if(delivery == null){
break;
}
}
Not an elegant solution and does not solve making multiple calls but you can use the MessageCount method. For example:
bool noAck = false;
var messageCount = channel.MessageCount("hello");
BasicGetResult result = null;
if (messageCount == 0)
{
// No messages available
}
else
{
while (messageCount > 0)
{
result = channel.BasicGet("hello", noAck);
var message = Encoding.UTF8.GetString(result.Body);
//process message .....
messageCount = channel.MessageCount("hello");
}
First declare instance of QueueingBasicConsumer() wich wraps the model.
From the model execute model.BasicConsume(QueueName, false, consumer)
Then implement a loop that will loop around messages from the queue which will then processing
Next line - consumer.Queue.Dequeue() method - waiting for the message to be received from the queue.
Then convert byte array to a string and display it.
Model.BasicAck() - release message from the queue to receive next message
And then on the server side can start waiting for the next message to come through:
public string GetMessagesByQueue(string QueueName)
{
var consumer = new QueueingBasicConsumer(_model);
_model.BasicConsume(QueueName, false, consumer);
string message = string.Empty;
while (Enabled)
{
//Get next message
var deliveryArgs = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
//Serialize message
message = Encoding.Default.GetString(deliveryArgs.Body);
_model.BasicAck(deliveryArgs.DeliveryTag, false);
}
return message;
}