Actually this was quite easy – when you know what's missing: The current post ID for the global
$wp_embed object, so it knows what to refer to. The reason is simple: oEmbeds get cached as post meta data, so without knowing the ID, the MarkUp can't get fetched and replaced in the content.
// grab a post from the database
/** @var \WP_Embed $wp_embed */
/** @var \WP_Post $post; */
// Add the fetched posts ID and add it to the global object
$wp_embed->post_ID = $post->ID;
// Execute the [embed] shortcode
$wp_embed->run_shortcode( $post->post_content );
// Execute the oEmbed handlers for plain links on the own line
$wp_embed->autoembed( $post->post_content );
More in depth info about oEmbed and caching can be found in a related answer by @birgire.