Caching queries not working as expected
The {% cache %} tag only caches the HTML output.  That's it.

In your example above, nothing is cached, and categoryProducts will be an empty set.

One thing you could do is to cache each entry individually:

{% set categoryProducts = craft.entries.section('products').relatedTo(category) %}
{% set categoryProducts = shuffle(categoryProducts) %}

{% for entry in categoryProducts %}
    {% cache globally using key 'product-' ~ entry.id %}
        ...
    {% endcache %}
{% endfor %}