ClickInventoryEvent cancelling and it's inventory use

SpongeAPI 7.1.0

When I try to close a player’s inventory using listener: ClickInventoryEvent

private void methodName(ClickInventoryEvent event, Player player) {
        ItemStackSnapshot itemStackSnapshot = event.getCursorTransaction().getDefault();
        event.setCancelled(true);

        if (ItemTypes.COAL.equals(itemStackSnapshot.getType())) {
            player.closeInventory();
        }
    }

I get a message:

[Server thread/WARN] [Sponge]: This player is currently modifying an open container. This action will be delayed.

But alright, this warning is described here:

I solved this question as follows
(no more warnings)

private void methodName(ClickInventoryEvent event, Player player) {
        ItemStackSnapshot itemStackSnapshot = event.getCursorTransaction().getDefault();
        event.setCancelled(true);

        if (ItemTypes.COAL.equals(itemStackSnapshot.getType())) {
            Task.builder()
                    .execute(() -> {
                        player.closeInventory();
                    })
                    .submit(plugin);
        }
}

but is this the most correct decision?

I think delaying like you did is the correct solution.

Okay, thanks.

I had a similar question,
maybe there are some suggestions, or I don’t understand something.

There is a problem like this:

Attempts to cancel the event fail:
(if I cancel the event correctly → event.setCancelled(true) )

private void onClickInventoryEvent(ClickInventoryEvent event, Player player) {
        ItemStackSnapshot itemStackSnapshot = event.getCursorTransaction().getDefault();
        event.setCancelled(true);

        DyeColor dyeColor = itemStackSnapshot.get(Keys.DYE_COLOR).orElse(DyeColors.BLACK);
        if (DyeColors.LIME.equals(dyeColor)) {
            if (tryToBuyItem(player)) {
event.getTargetInventory().query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(2, 5)))
                        .set(ItemStack.builder()
                                .itemType(ItemTypes.STAINED_GLASS_PANE)
                                .add(Keys.DYE_COLOR, DyeColors.LIME)
                                .add(Keys.DISPLAY_NAME, textCreator.fromLegacy("&6Buy"))
                                .add(Keys.ITEM_LORE, Arrays.asList(
                                        textCreator.fromLegacy("&3Balance&8: &2" + balance))
                                .quantity(1)
                                .build());

            }
}

^ in this case, the item is not changed in the inventory

As in the case above, using the Task.Builder helps:
(but I don’t really like this solution)

private void onClickInventoryEvent(ClickInventoryEvent event, Player player) {
        ItemStackSnapshot itemStackSnapshot = event.getCursorTransaction().getDefault();
        event.setCancelled(true);

        DyeColor dyeColor = itemStackSnapshot.get(Keys.DYE_COLOR).orElse(DyeColors.BLACK);
        if (DyeColors.LIME.equals(dyeColor)) {
            if (tryToBuyItem(player)) {
                 Task.builder()
                        .execute(() -> event.getTargetInventory().query(QueryOperationTypes.INVENTORY_PROPERTY.of(SlotPos.of(2, 5)))
                                    .set(ItemStack.builder()
                                .itemType(ItemTypes.STAINED_GLASS_PANE)
                                .add(Keys.DYE_COLOR, DyeColors.LIME)
                                .add(Keys.DISPLAY_NAME, textCreator.fromLegacy("&6Buy"))
                                .add(Keys.ITEM_LORE, Arrays.asList(
                                        textCreator.fromLegacy("&3Balance&8: &2" + balance))
                                .quantity(1)
                                .build());
                        .submit(HMVote.getInstance());

            }
}

But @JBYoshi tells, that:
... Try cancelling the event so Sponge doesn’t make those changes.

what am I doing wrong?