Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

concurrently #23

Open
SamuelMwangiW opened this issue Apr 28, 2022 · 9 comments
Open

concurrently #23

SamuelMwangiW opened this issue Apr 28, 2022 · 9 comments

Comments

@SamuelMwangiW
Copy link
Owner

SamuelMwangiW commented Apr 28, 2022

Add ability to execute requests concurrently e.g sending messages, disbursing airtime, mobile checkout, voice calls, etc.

Use Http::pool()

$responses = Http::pool(fn (Pool $pool) => [
    $pool->get('http://localhost/first'),
    $pool->get('http://localhost/second'),
    $pool->get('http://localhost/third'),
]);

Or

$responses = \JustSteveKing\Transporter\Facades\Concurrently::build()->setRequests([
    \SamuelMwangiW\Africastalking\Transporter\Requests\Airtime\SendRequest::build()
        ->withToken('foobar')
        ->withData([
        'title' => 'Build a package'
    ]),
    \SamuelMwangiW\Africastalking\Transporter\Requests\Airtime\SendRequest::build()
        ->withToken('foobar')
        ->withData([
        'title' => 'Build a package'
    ]),
    \SamuelMwangiW\Africastalking\Transporter\Requests\Airtime\SendRequest::build()
        ->withToken('foobar')
        ->withData([
        'title' => 'Build a package'
    ]),
]);

$responses[0]->json();
$responses[1]->json();
$responses[2]->json();

Or use Guzzle

@SamuelMwangiW SamuelMwangiW added enhancement New feature or request good first issue Good for newcomers labels Apr 28, 2022
@SamuelMwangiW SamuelMwangiW removed enhancement New feature or request good first issue Good for newcomers labels Jan 19, 2023
@SamuelMwangiW
Copy link
Owner Author

SamuelMwangiW commented Jan 19, 2023

Switched from laravel-transporter to Saloon.

Whereas I can make it work, I don't see a huge need for this feature at the moment. Will reopen should that change.

I will also explore once Pooling support is added with saloonphp/saloon#64

@Sammyjo20
Copy link

Hey @SamuelMwangiW I have been writing the documentation on request pooling if you are interested, feel free to give any feedback too! It's still in progress, but almost finished :)

https://docs.saloon.dev/v/2/digging-deeper/concurrency-and-pools

@SamuelMwangiW
Copy link
Owner Author

Thanks so much @Sammyjo20; pleasantly surprised you bumped into this pet project 😄 .

I will most definitely upgrade to v2 and share any feedback I may have.

Thanks you for the incredible work on Saloon 👏

@Sammyjo20
Copy link

That's awesome @SamuelMwangiW it's so good to hear Saloon is being used and you love it :D

Great little SDK here, I have added it to the showcase in the v2 docs too 👍

@SamuelMwangiW
Copy link
Owner Author

SamuelMwangiW commented Jan 22, 2023

Thank you so much @Sammyjo20 for your kind words and for adding my 2 little SDKs on the showcase page on the new Saloon docs.

Adding quick appreciation message for Pooling feature in v2.

With the tests below, time to send 200 Text Messages came down from 2 Minutes to a mere 4 Seconds 🤯 on my crappy connection at home

test('benchmark pooling requests', function (string $phone) {
    $messages = collect(fake()->sentences(200));

    // 4915.749416 ms
    $pool = Benchmark::measure(function () use ($phone, $messages) {
        $requests = [];

        $messages->each(function (string $message) use ($phone, &$requests) {
            $requests[] = BulkSmsRequest::make(['message' => $message, 'to' => $phone]);
        });

        $connector = AfricastalkingConnector::make();
        $connector->service(Service::BULK_SMS);
        $pool = $connector->pool($requests);
        $pool->setConcurrency(10);

        $promise = $pool->send();
        $promise->wait();
    });

    // 157157.544833 ms
    $individually = Benchmark::measure(
        fn() => $messages->each(
            fn(string $message) => africastalking()->sms($message)->to($phone)->send()
        )
    );

    dd($individually, $pool); //157157.544833 4915.749416 
})->with('phone-numbers');

Thank you once again for the incredible work on v2, the DX is on another level 🚀

@Sammyjo20
Copy link

Whoa... That's insane...!! I've never seen it perform that well. Thanks for sharing that with me!

Can't wait to release v2 😀

@Sammyjo20
Copy link

Some other interesting results, looks like even by just using the same connector now it can massively boost performance. My guess is that Guzzle is keeping the CURL connection open or something like that

$newConnector = Benchmark::measure(function () {
        Forge::make()->send(new IndexServers());
        Forge::make()->send(new IndexServers());
        Forge::make()->send(new IndexServers());
    });

$sameConnector = Benchmark::measure(function () {
    $forge = new Forge;

    $forge->send(new IndexServers());
    $forge->send(new IndexServers());
    $forge->send(new IndexServers());
});

dd($newConnector, $sameConnector);

// $newConnector: 1109ms
// $sameConnector: 626ms

@SamuelMwangiW
Copy link
Owner Author

SamuelMwangiW commented Jan 22, 2023

Thanks @Sammyjo20. I agree that using the same connector leads to a significant reduction in execution time.

I updated my test to below to send out 200 SMS message. Whereas using pool was still faster, I think the concurrency could be the difference

$messages = collect(fake()->sentences(200));
$phone = fake()->e164PhoneNumber();

$pool = Benchmark::measure(function () use ($phone, $messages) {
    $requests = [];

    $messages->each(function (string $message) use ($phone, &$requests) {
        $data = [
            'message' => $message,
            'to' => $phone,
            'from' => config(key: 'africastalking.from')
        ];

        $requests[] = BulkSmsRequest::make($data);
    });

    $connector = AfricastalkingConnector::make();
    $connector->service(Service::BULK_SMS);
    $pool = $connector->pool($requests,10);

    $promise = $pool->send();
    $promise->wait();
});

$sameConnector = Benchmark::measure(function () use ($phone, $messages) {
    $connector = AfricastalkingConnector::make()->service(Service::BULK_SMS);

    $messages->each(function (string $message) use ($connector, $phone) {
        $data = [
            'message' => $message,
            'to' => $phone,
            'from' => config(key: 'africastalking.from')
        ];

        $connector->send(BulkSmsRequest::make($data));
    });
});

dd($pool,$sameConnector);

// $pool: 4s
// $sameConnector:  35s

@Sammyjo20
Copy link

Oh yeah totally, it makes a big difference. I'm glad that with v2, instantiating the connector is the recommended way to send requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants