Where and how to conditionally redirect old aliases to new aliases We are replacing a website with a new version. The domain is the same, but URL aliases in the new website are different. 

In many cases, I can use an old alias to calculate its corresponding new alias. There are many thousands of old aliases, so I don't want to just use the Redirect module. I know how to write the calculations and how to check if a calculated new alias exists.

I need to know at what point I can intercept each incoming URL to calculate a new alias.

I also need to know how to redirect to the calculated new alias if it exists.

Concrete example:

A book chapter on the old site is at example.com/recent/secrets-to-success/10-knowing-when-to-quit. This chapter on the new site is at example.com/secrets-to-success/knowing-when-quit. The difference is (a) we no longer add the recent subfolder, (b) we've removed chapter numbers from chapter titles, and (c) we've changed which words are ignored when an alias is auto-generated.

When someone uses an old alias, I want to intercept it, calculate the new alias, check if it exists, and redirect to it if it does. This is only one example. There are several other ways of calculating, so there's some trial and error involved. But I know how to take care of that.
This solution is based on a suggestion by @4k4 at Redirect from within controller always goes to home page. 

My custom module is named rsc.

In modules/custom/rsc the file rsc.services.yml includes the following:

services:
  rsc.event.Redirect404:
    class: Drupal\rsc\EventSubscriber\rscRedirect404
    tags:
      - {name: event_subscriber}


In modules/custom/rsc/src/EventSubscriber the file rscRedirect404.php contains the following:

&lt;?php
namespace Drupal\rsc\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

class rscRedirect404 extends HttpExceptionSubscriberBase {

  protected function getHandledFormats() { // required
    return ['html'];
  }

  public function on404(GetResponseForExceptionEvent $event) {

    $path = \Drupal::request()-&gt;getPathInfo();
    $path = [code to modify the path from old site to new site]

    if (($url = \Drupal::service('path.validator')-&gt;getUrlIfValid($path))) {
      $event-&gt;setResponse(new RedirectResponse(URL::fromUserInput($path)-&gt;toString()));
    }
  }
}


With this in place, I see 404 redirects before they get passed to the default handler. If I do the $event-&gt;setResponse(), the user is redirected as I specify. If not, normal processing occurs.

In reality, the line that says [code to modify the path from old site to new site] is multiple lines where I do several trial-and-error tests to figure out the correct new URL,  but everything else is just as I'm using it.