Why not queue the logic, you can fire an event on inbound webhook event, then have various listeners to run in via queue worker.
Handling webhooks from an external service
Hi everyone!
I've this method below which serves as an API that fetchs data from an external service to populate the database.
The external service set up a cron every 3 minutes and calls this method by chunking the payload.. (webhook)
so every 3 minutes they are calling this api 20 times ( for every chunk)..
main method
public function handleUpsertFeed(UpsertRequest $request)
{
$validatedData = $request->validated();
$feeds = $validatedData['feeds'];
foreach ($feeds as $feed) {
$checkIntergation = FeedIntegration::whereIntegrationId($feed['integration_id'])->first();
if (!$checkIntergation) {
$this->createUpsertFeed($feed);
} else {
$this->updateUpsertFeed($checkIntergation->feed_id, $feed);
}
}
return response()->json([
'status' => true
], 200);
}
createUpsertFeed method
public function createUpsertFeed($feed)
{
DB::transaction(function () use ($feed) {
$guid = Uuid::generate()->string;
// Create external feed
$externalFeed = ExternalFeed::create([
'guid' => $guid,
'internal_alias' => $feed['name'],
'last_color' => $feed['color'],
'last_message' => $feed['message'],
]);
$newFeed = Feed::create([
'name' => $feed['name'],
'description' => $feed['description'],
'type' => 'external',
'dependencies' => (isset($feed['dependencies'])) ? $this->handleDependencies($feed) : '[]',
'space_id' => $feed['spaceId'],
'last_reported_status' => $feed['color'],
'override_color' => $feed['color'],
'last_reported_message' => $feed['message'],
'last_state_changed_at' => $feed['updatedAt'],
'last_updated_at' => Carbon::now()
]);
FeedIntegration::create([
'feed_id' => $newFeed->id,
'integration_id' => $feed['integration_id'],
'external_feed_guid' => $guid
]);
$newFeed->pages()->attach($feed['pageId']);
$tags = isset($feed['custom_data']['tags']) ? $feed['custom_data']['tags'] : null;
if ($tags) {
$tagIds = $this->handleTags($tags);
$newFeed->tags()->sync($tagIds);
}
});
return true;
}
updateUpsertFeed method
public function updateUpsertFeed($feedId, $newFeed)
{
$checkFeed = Feed::find($feedId);
if ($checkFeed) {
DB::transaction(function () use ($checkFeed, $newFeed) {
$previousFeedState = new FeedState($checkFeed->last_reported_status, $checkFeed->last_reported_message, $checkFeed->last_state_changed_at);
$checkFeed->update([
'name' => $newFeed['name'],
'description' => $newFeed['description'],
'space_id' => $newFeed['spaceId'],
'dependencies' => (isset($newFeed['dependencies'])) ? $this->handleDependencies($newFeed) : '[]',
'last_reported_status' => $newFeed['color'],
'override_color' => $newFeed['color'],
'last_reported_message' => $newFeed['message'],
'last_state_changed_at' => $newFeed['updatedAt'],
'last_updated_at' => Carbon::now()
]);
$checkFeed->pages()->sync($newFeed['pageId']);
$tags = isset($newFeed['custom_data']['tags']) ? $newFeed['custom_data']['tags'] : null;
if ($tags) {
$tagIds = $this->handleTags($tags);
$checkFeed->tags()->sync($tagIds);
}
$newFeedState = new FeedState($checkFeed->last_reported_status, $checkFeed->last_reported_message, Carbon::now("utc")->format("Y-m-d H:i:s"));
$feedHasChangedState = $previousFeedState->color != $newFeedState->color ?? true;
$isNotDefault = $checkFeed->last_reported_status != 'default';
if ($feedHasChangedState && $isNotDefault) {
event(new FeedStateChanged($checkFeed, $previousFeedState, $newFeedState));
}
});
}
return true;
}
Helpers methods :
public function handleDependencies($feed)
{
$localDependencies = [];
if (count($feed['dependencies']) > 0) {
foreach ($feed['dependencies'] as $dependency) {
if ($dependency['type'] == 'integration_id') {
$checkIntegration = FeedIntegration::whereIntegrationId($dependency['id'])->first();
$checkIntegration ? $localDependencies[] = $checkIntegration->feed_id : "";
}
if ($dependency['type'] == 'feed_id') {
$checkFeed = Feed::find($dependency['id']);
$checkFeed ? $localDependencies[] = $checkFeed->id : "";
}
}
}
return json_encode($localDependencies);
}
public function handleTags($tags)
{
$ids = [];
$tagValues = explode(',', $tags);
foreach ($tagValues as $tag) {
$newTag = Tag::firstOrCreate(
['name' => $tag],
['name' => $tag]
);
$ids[] = $newTag->id;
}
return $ids;
}
As you can see many database calls and I'm concerned about performance..
Is handling chunks from my side would be a better approach?
otherwise is throttling the request a good idea too?
I'm eager for your suggestions! Thanks!
Please or to participate in this conversation.