Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel patterns - Usage of jobs vs services

I was wondering how most developers use this two Laravel tools.

In Laravel, you can handle business logic with Services, or with Jobs (let's talk only about not-queueable jobs, only those ones that run in the same process).

For example, an user wants to create an entity, let's say a Book, you can handle the entity creation with a service or dispatching a job.

Using a job it would be something like this:

class PostBook extends Job
{
    ...
    public function handle(Book $bookEntity)
    {
        // Business logic here.
    }
    ...
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        dispatch(new PostBook($request->all()));
        ...
    }
}

Using a service, it would be something like this:

class BookService
{
    public function store(Request $request)
    {
        // Business logic here.
    }
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        // I could inject the service instead.
        $bookService = $this->app()->make(App\Services\BookService::class);
        $bookService->store($request);
        ...
    }
}

The question is, how do you mostly choose to use one way or the other one? And why?

Surely there are two "schools" in this matter, but I would want to understand pros & cons of each one.

like image 598
Facundo Fasciolo Avatar asked Oct 19 '18 15:10

Facundo Fasciolo


People also ask

What is the use of Laravel jobs?

Laravel gives us a built-in queue system that helps us to run tasks in the background and configure how the system should react in different situations. It allows you to delay a time-consuming task until a later time. By postponing the time-consuming task, you can improve the performance of the Laravel applications.

Are Laravel jobs asynchronous?

Laravel Jobs are not asynchronous.

Is Laravel synchronous or asynchronous?

An asynchronous request is a request that is executed in the background, so you don't have to wait for the response to continue your code. The Laravel HTTP Client has the async() method for that.


1 Answers

"Business logic" can be handled with anything, so it seems like what's really being asked is which option is better for repeating the same business logic without repeating code.

A Job class typically does one thing, as defined by its handle() method. It's difficult to exclude queued jobs from the comparison because running them synchronously usually defeats the purpose, which is to handle slow, expensive, or unreliable actions (such as calling a web API) after the current request has been completed and a response has been shown to the user.

If all jobs were expected to be synchronous, it wouldn't be much different than defining a function for your business logic. That's actually very close to what dispatching a synchronous job does: Somewhere down the call stack it ends up running call_user_func([$job, 'handle']) to invoke a single method on your job object. More importantly, a synchronous job lacks the mechanism for retrying jobs that might have failed due to external causes such as network failures.

Services, on the other hand, are an easy way to encapsulate the logic around a component, and they may do more than one thing. In this context, a component may be thought of as a piece of your application that could be swapped out for a different implementation without having to modify code that was using it. A perfect example, included in the framework, is the Filesystem service (most commonly accessed with the Storage facade).

Consider if you didn't store books by inserting them into your database, but instead by posting to an external API. You may have a BookRepository service that not only has a store() method, but also has a get(), update(), list(), delete(), or any number of other methods. All of these requests share logic for authenticating to the external web service (like adding headers to requests), and your BookRepository class can encapsulate that re-usable logic. You can use this service class inside of scheduled artisan commands, web controllers, api controllers, jobs, middleware, etc. — without repeating code.

Using this example, you might create a Job for storing a new book so you don't make users wait when there are slow API responses (and it can retry when there are failures). Internally, your job calls your Service's store() method when it runs. The work done by the service is scheduled by the job.

like image 191
Travis Britz Avatar answered Sep 18 '22 12:09

Travis Britz