SamuelMwangiW / africastalking-laravel

An Elegant Laravel SDK for interacting with Africa's Talking APIs
MIT License
6 stars 2 forks source link

concurrently #23

Open SamuelMwangiW opened 2 years ago

SamuelMwangiW commented 2 years ago

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 commented 1 year ago

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 https://github.com/Sammyjo20/Saloon/issues/64

Sammyjo20 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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