feat: 🎸 create orchestrator
In this PR:
1. we centralize all the operations on the graph, within DatasetOrchestrator:
  - `.set_revision`: used by the webhook, sets the current git revision for a dataset, which will refresh the "root" steps that has a different revision (and by cascade, all the graph)
  - `.finish_job`: used by the workers (and by the zombies/long job killers) to finish a job, put the data in the cache, and create the new jobs if needed (it also deletes duplicate jobs if any)
  - `.has_some_cache`: used in the API endpoints, when a cache entry is not found. It's an implementation detail:
    - if the dataset has no cache entry, we do a call to the Hub to get the revision -> if we get an answer, we create the jobs with the revision, if not we return 404 (the dataset does not exist, or is not supported).
    - else: if the cache already has entries, we will check if the asked cache entry could exist at one point (see `.has_pending_ancestor_jobs` below)
  - `.has_pending_ancestor_jobs`: used in the API endpoints, when a cache entry is not found and the dataset already has some other cache entries. It checks if the requested steps, or any of their ancestors, has some pending jobs. If so, we ask the user to retry later, else: 404 because the cache entry will never exist (possibly the config or the split parameter is wrong)
  - `.backfill`: a full analysis of the cache and queue for a dataset, to determine if the state is normal, and if not, which jobs should be created or deleted.
2. use the appropriate orchestrator methods (which try to be as fast as possible) instead of the previous behavior, which was to always call `.backfill`, and was too heavy with unnecessary operations, in particular for datasets with a lot of configs or splits.

Also note that the jobs should now be finished with the correct status: SUCCESS or ERROR. Until now (since we used backfill), they were all put in CANCELLED status, which didn't help with monitoring.
feat: 🎸 create orchestrator: In this PR:
1. we centralize all the operations on the graph, within DatasetOrchestrator:
  - `.set_revision`: used by the webhook, sets the current git revision for a dataset, which will refresh the "root" steps that has a different revision (and by cascade, all the graph)
  - `.finish_job`: used by the workers (and by the zombies/long job killers) to finish a job, put the data in the cache, and create the new jobs if needed (it also deletes duplicate jobs if any)
  - `.has_some_cache`: used in the API endpoints, when a cache entry is not found. It's an implementation detail:
    - if the dataset has no cache entry, we do a call to the Hub to get the revision -> if we get an answer, we create the jobs with the revision, if not we return 404 (the dataset does not exist, or is not supported).
    - else: if the cache already has entries, we will check if the asked cache entry could exist at one point (see `.has_pending_ancestor_jobs` below)
  - `.has_pending_ancestor_jobs`: used in the API endpoints, when a cache entry is not found and the dataset already has some other cache entries. It checks if the requested steps, or any of their ancestors, has some pending jobs. If so, we ask the user to retry later, else: 404 because the cache entry will never exist (possibly the config or the split parameter is wrong)
  - `.backfill`: a full analysis of the cache and queue for a dataset, to determine if the state is normal, and if not, which jobs should be created or deleted.
2. use the appropriate orchestrator methods (which try to be as fast as possible) instead of the previous behavior, which was to always call `.backfill`, and was too heavy with unnecessary operations, in particular for datasets with a lot of configs or splits.

Also note that the jobs should now be finished with the correct status: SUCCESS or ERROR. Until now (since we used backfill), they were all put in CANCELLED status, which didn't help with monitoring.