Laravel Event exceeds Pusher allowed limit

Multi tool use
Multi tool use


Laravel Event exceeds Pusher allowed limit



I have an event in my Laravel application that for specific records it exceeds the allowed maximum limit (10240 bytes) of Pusher. Is it correct that Laravel serializes every public attribute on the Event class? If so I suspect that the serialized model should not exceed the 10kb limit but it fails anyway. Are there any approaches to decrease the size of the data content?


class PostChanged implements ShouldBroadcast
{

use Dispatchable, InteractsWithSockets, SerializesModels;

public $post;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Post $post)
{
$this->post = $post;
}

/**
* Get the channels the event should broadcast on.
*
* @return IlluminateBroadcastingChannel|array
*/
public function broadcastOn()
{
return new Channel('post-channel.'.$this->post->id);
}

public function broadcastWith()
{
$extra = [
'data' => $this->post->data,
];

return array_merge($this->post->toArray(), $extra);
}
}



produces:


The data content of this event exceeds the allowed maximum (10240 bytes).
See http://pusher.com/docs/server_api_guide/server_publishing_events for more info





What are the contents of $post? Also, why are you adding $post->data twice? It's already contained in the $post variable.
– Jerodev
Jul 3 at 6:50


$post


$post->data


$post





The code I have posted is just an example of my code to show my implementation. It is not the actual code. My question was regarding the serialization or not of the $post object.
– sarotnem
Jul 3 at 9:46



$post




3 Answers
3



Approach 1: Resolve at client side



The most reliable approach would be what @ExohJosh described: Only send the event type along with an ID so the client (most likely JavaScript) can fetch the updated record through a separate REST (or whatever) API.


public function broadcastWith()
{
return [
'id' => $this->post->id,
];
}



Approach 2: Reduce Payload



An alternative (and simpler) approach would be to send only the data required by the client (the one you figured out yourself @sarotnem). However this approach is only safe, if you definitely know that the attributes you submit can not in any case exceed the 10KiB limit. This can be ensured through input validation, limitations on DB columns or other means.



When choosing this approach, be sure to also include the size of any relationships, that could possibly be loaded on the model, into your calculations.



A neat way to define an "external representation" of a model are Laravel's API Resources. They could make your code look like this:


public function broadcastWith()
{
return [
'post' => new AppHttpResourcesPostResource($this->post),
];
}



where AppHttpResourcesPostResource could be:


AppHttpResourcesPostResource


class PostResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'body' => $this->body,
];
}
}



An approach I have taken to this in the past when working with large objects is to consider segregation of the large object or pass a reference of the object EG: the id and then do the additional functionality in the event listener.



An approach in the case of a post changing could be:



The post is changed on client 1.



Backend lets pusher know the post has changed and receives the id



Pusher broadcasts to client 2



client 2 is listening and hits the endpoint to get a client by id



If this approach isn't going to work for you – You need to check if the object you are serialising has any redundancies in data, if you are passing too much there is an issue there.





But passing only a reference isn't what serialization basically does with passing only the id of the object? That's why I'm thinking serialization does not take place, at least automatically.
– sarotnem
Jul 3 at 11:54





Generally serialization means just transforming an object for storage or transmission. However, when a Laravel Job or Event uses the SerializesModels trait, this does exactly what you describe. It passes the id on event emission and restores the model from the db on execution of the handler. But this has nothing to do with what you broadcast through pusher. If you send the (deserialized) object to pusher, it just takes it. Otherwise, your client would have to know how to restore the object through your REST (or whatever) API by ID.
– jsphpl
Jul 3 at 14:14



SerializesModels





@jsphpl Correct me if I'm wrong but by using the SerializesModels trait, shouldn't Laravel broadcast to pusher only the id of the object? Instead if I dd() in IlluminateBroadcastingBroadcastEvent.php@getPayloadFromEvent($event) the full object is returned
– sarotnem
Jul 3 at 15:00



SerializesModels


dd()


IlluminateBroadcastingBroadcastEvent.php@getPayloadFromEvent($event)





@sarotnem no. It "pseudo-serializes" the model (by passing its id and restoring it from db) while your job/event is in the queue – this is what SerializesModels does. At the time when the event is being broadcast to pusher, the model has already been restored. The model is in this "serialized-to-class+id" state only while the job is in the queue. At the moment the job/event is being handled, laravel will restore the model from the database.
– jsphpl
Jul 3 at 17:15


SerializesModels



After quite a lot of experimenting I've managed to get it working by simply unsetting some unnecessary values of the array produced by $post->toArray().


$post->toArray()



Also I noticed that the broadcastWith() method returns the payload as an array and not serialised.


broadcastWith()






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

eK7p,I4dzH,YK3Lp
PO,G1z0P,iPL8MihIHmc8jNAC9B5N9lmChbbbCt45uoV JPg z HN6P dmIEHqyD

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications