bavix / laravel-wallet

It's easy to work with a virtual wallet
https://bavix.github.io/laravel-wallet/
MIT License
1.14k stars 230 forks source link

balance udpate is not happening in Nova Action #455

Closed sinamiandashti closed 2 years ago

sinamiandashti commented 2 years ago

Hi

I tried to deposit balance to a user wallet inside a Nova Action

but the balance of the wallet is not updating ... I'm not sure if it depends to Locking mecansim or queue of laravel nova actions

but the balance is not updating

any suggestion ?

rez1dent3 commented 2 years ago

Hello. Provide the code with which you change the balance. In general, you cannot change the balance parameter directly.

sinamiandashti commented 2 years ago
public function handle(ActionFields $fields, Collection $models)
    {
        $title = 'Panel Transaction';
        $meta = ['description' => $fields->description,'title' => $title];
        /** @var User $model */
      foreach ($models as $model) {
            $model = $model->deposit($fields->amount, $meta);
             $this->markAsFinished($model);
       }

        return Action::message('Site balance updated successfully!');
    }
sinamiandashti commented 2 years ago

when this code executed via laravel nova action , the transaction record is created in DB , but the balance is not updated

but when I normally call "deposit" in other areas (like in controllers) it works

I did some investigation and find out that BookkeeperService::sync is not getting called inside laravel nova action somehow

I'm still investigating why

ysfkaya commented 2 years ago

I have the same issue. When I run the refreshBalance method after making a deposit, the balance is updated, but other than that, it does not.

Version: ^7.3 Laravel: ^8 Nova: ^3

/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    $model = $models->first();

    $model->depositFloat($fields->amount, [
        'label' => $fields->label,
        'notes' => $fields->notes,
    ]);

    return $model;
}

/**
 * Handle chunk results.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  array  $results
 * @return mixed
 */
public function handleResult(ActionFields $fields, $results)
{
    $result = parent::handleResult($fields, $results);

    if($result instanceof Model) {
        $result->wallet->refreshBalance();
    }

    return $result;
}
sinamiandashti commented 2 years ago

yeah it has something to do with the locking/blocking

as a workaround a dispatch a job to do the deposit async @ysfkaya

rez1dent3 commented 2 years ago

@sinamiandashti @ysfkaya Thank you. I'll try to debug this part this week. I have never tried to update the balance through nova. The admin panel was used only for displaying information.

rez1dent3 commented 2 years ago

@sinamiandashti @ysfkaya At the moment, the solution is to put rollback in the first line. In the future, I will think about a solution out of the box, while there are no ideas.

use Illuminate\Support\Facades\DB;
...
public function handle(ActionFields $fields, Collection $models)
{
    DB::rollBack(0);
...
}
sinamiandashti commented 2 years ago

If you can explain me how locking is working (or maybe in documentation) I could think about the solution or if u can explain me the solution I can create a pull request and contribute

rez1dent3 commented 2 years ago

It's not about blocking, but about the transaction that laravel nova hangs on the whole action.

The package should now be able to correctly implement the saga (db + cache). We throw the balance into the cache and hang a lock for all operations.

In case of an erroneous transaction, we should not update the data in the cache.

You can read more about the state in a transaction here: https://github.com/bavix/laravel-wallet/pull/412

ibrunotome commented 2 years ago

@rez1dent3 the same is happening if you run transactions in a migration, the balance in the wallet is only updated with DB::rollBack(0); at the beginning.

rez1dent3 commented 2 years ago

@ibrunotome Yes, that's right. This is due to the framework transaction starting. If the package completely removes the fight against the race condition, then you can allow the use of framework transactions.

Right now, I'm leaning towards adding a new exception that will tell the client about the transaction that was fired above. This will get rid of obvious errors.

rez1dent3 commented 2 years ago

At the moment there is only one solution to these cases. If I come up with a different solution, I'll be sure to update the documentation. Now the performance of the package is in the foreground.

Working with the internal state accelerated the package twice. https://github.com/bavix/laravel-wallet-benchmark/

https://19b01766.laravel-wallet.pages.dev/#/nova-action

Снимок экрана 2022-03-31 в 20 26 55