We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[callbacks] call on_*_end events in reverse order


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `hydra/core/callbacks.py`
Content:
```
1 # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
2 import warnings
3 from typing import Any
4 
5 from omegaconf import DictConfig
6 
7 from hydra.core.utils import JobReturn
8 from hydra.utils import instantiate
9 
10 
11 class Callbacks:
12     def __init__(self, config: DictConfig) -> None:
13         self.callbacks = []
14         for params in config.hydra.callbacks.values():
15             self.callbacks.append(instantiate(params))
16 
17     def _notify(self, function_name: str, **kwargs: Any) -> None:
18         for c in self.callbacks:
19             try:
20                 getattr(c, function_name)(**kwargs)
21             except Exception as e:
22                 warnings.warn(
23                     f"Callback {type(c).__name__}.{function_name} raised {type(e).__name__}: {e}"
24                 )
25 
26     def on_run_start(self, config: DictConfig, **kwargs: Any) -> None:
27         self._notify(function_name="on_run_start", config=config, **kwargs)
28 
29     def on_run_end(self, config: DictConfig, **kwargs: Any) -> None:
30         self._notify(function_name="on_run_end", config=config, **kwargs)
31 
32     def on_multirun_start(self, config: DictConfig, **kwargs: Any) -> None:
33         self._notify(function_name="on_multirun_start", config=config, **kwargs)
34 
35     def on_multirun_end(self, config: DictConfig, **kwargs: Any) -> None:
36         self._notify(function_name="on_multirun_end", config=config, **kwargs)
37 
38     def on_job_start(self, config: DictConfig, **kwargs: Any) -> None:
39         self._notify(function_name="on_job_start", config=config, **kwargs)
40 
41     def on_job_end(
42         self, config: DictConfig, job_return: JobReturn, **kwargs: Any
43     ) -> None:
44         self._notify(
45             function_name="on_job_end", config=config, job_return=job_return, **kwargs
46         )
47
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/hydra/core/callbacks.py b/hydra/core/callbacks.py
--- a/hydra/core/callbacks.py
+++ b/hydra/core/callbacks.py
@@ -14,8 +14,9 @@
         for params in config.hydra.callbacks.values():
             self.callbacks.append(instantiate(params))
 
-    def _notify(self, function_name: str, **kwargs: Any) -> None:
-        for c in self.callbacks:
+    def _notify(self, function_name: str, reverse: bool = False, **kwargs: Any) -> None:
+        callbacks = reversed(self.callbacks) if reverse else self.callbacks
+        for c in callbacks:
             try:
                 getattr(c, function_name)(**kwargs)
             except Exception as e:
@@ -27,13 +28,15 @@
         self._notify(function_name="on_run_start", config=config, **kwargs)
 
     def on_run_end(self, config: DictConfig, **kwargs: Any) -> None:
-        self._notify(function_name="on_run_end", config=config, **kwargs)
+        self._notify(function_name="on_run_end", config=config, reverse=True, **kwargs)
 
     def on_multirun_start(self, config: DictConfig, **kwargs: Any) -> None:
         self._notify(function_name="on_multirun_start", config=config, **kwargs)
 
     def on_multirun_end(self, config: DictConfig, **kwargs: Any) -> None:
-        self._notify(function_name="on_multirun_end", config=config, **kwargs)
+        self._notify(
+            function_name="on_multirun_end", reverse=True, config=config, **kwargs
+        )
 
     def on_job_start(self, config: DictConfig, **kwargs: Any) -> None:
         self._notify(function_name="on_job_start", config=config, **kwargs)
@@ -42,5 +45,9 @@
         self, config: DictConfig, job_return: JobReturn, **kwargs: Any
     ) -> None:
         self._notify(
-            function_name="on_job_end", config=config, job_return=job_return, **kwargs
+            function_name="on_job_end",
+            config=config,
+            job_return=job_return,
+            reverse=True,
+            **kwargs,
         )

{"golden_diff": "diff --git a/hydra/core/callbacks.py b/hydra/core/callbacks.py\n--- a/hydra/core/callbacks.py\n+++ b/hydra/core/callbacks.py\n@@ -14,8 +14,9 @@\n         for params in config.hydra.callbacks.values():\n             self.callbacks.append(instantiate(params))\n \n-    def _notify(self, function_name: str, **kwargs: Any) -> None:\n-        for c in self.callbacks:\n+    def _notify(self, function_name: str, reverse: bool = False, **kwargs: Any) -> None:\n+        callbacks = reversed(self.callbacks) if reverse else self.callbacks\n+        for c in callbacks:\n             try:\n                 getattr(c, function_name)(**kwargs)\n             except Exception as e:\n@@ -27,13 +28,15 @@\n         self._notify(function_name=\"on_run_start\", config=config, **kwargs)\n \n     def on_run_end(self, config: DictConfig, **kwargs: Any) -> None:\n-        self._notify(function_name=\"on_run_end\", config=config, **kwargs)\n+        self._notify(function_name=\"on_run_end\", config=config, reverse=True, **kwargs)\n \n     def on_multirun_start(self, config: DictConfig, **kwargs: Any) -> None:\n         self._notify(function_name=\"on_multirun_start\", config=config, **kwargs)\n \n     def on_multirun_end(self, config: DictConfig, **kwargs: Any) -> None:\n-        self._notify(function_name=\"on_multirun_end\", config=config, **kwargs)\n+        self._notify(\n+            function_name=\"on_multirun_end\", reverse=True, config=config, **kwargs\n+        )\n \n     def on_job_start(self, config: DictConfig, **kwargs: Any) -> None:\n         self._notify(function_name=\"on_job_start\", config=config, **kwargs)\n@@ -42,5 +45,9 @@\n         self, config: DictConfig, job_return: JobReturn, **kwargs: Any\n     ) -> None:\n         self._notify(\n-            function_name=\"on_job_end\", config=config, job_return=job_return, **kwargs\n+            function_name=\"on_job_end\",\n+            config=config,\n+            job_return=job_return,\n+            reverse=True,\n+            **kwargs,\n         )\n", "issue": "[callbacks] call on_*_end events in reverse order\n\n", "before_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved\nimport warnings\nfrom typing import Any\n\nfrom omegaconf import DictConfig\n\nfrom hydra.core.utils import JobReturn\nfrom hydra.utils import instantiate\n\n\nclass Callbacks:\n    def __init__(self, config: DictConfig) -> None:\n        self.callbacks = []\n        for params in config.hydra.callbacks.values():\n            self.callbacks.append(instantiate(params))\n\n    def _notify(self, function_name: str, **kwargs: Any) -> None:\n        for c in self.callbacks:\n            try:\n                getattr(c, function_name)(**kwargs)\n            except Exception as e:\n                warnings.warn(\n                    f\"Callback {type(c).__name__}.{function_name} raised {type(e).__name__}: {e}\"\n                )\n\n    def on_run_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_run_start\", config=config, **kwargs)\n\n    def on_run_end(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_run_end\", config=config, **kwargs)\n\n    def on_multirun_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_multirun_start\", config=config, **kwargs)\n\n    def on_multirun_end(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_multirun_end\", config=config, **kwargs)\n\n    def on_job_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_job_start\", config=config, **kwargs)\n\n    def on_job_end(\n        self, config: DictConfig, job_return: JobReturn, **kwargs: Any\n    ) -> None:\n        self._notify(\n            function_name=\"on_job_end\", config=config, job_return=job_return, **kwargs\n        )\n", "path": "hydra/core/callbacks.py"}], "after_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved\nimport warnings\nfrom typing import Any\n\nfrom omegaconf import DictConfig\n\nfrom hydra.core.utils import JobReturn\nfrom hydra.utils import instantiate\n\n\nclass Callbacks:\n    def __init__(self, config: DictConfig) -> None:\n        self.callbacks = []\n        for params in config.hydra.callbacks.values():\n            self.callbacks.append(instantiate(params))\n\n    def _notify(self, function_name: str, reverse: bool = False, **kwargs: Any) -> None:\n        callbacks = reversed(self.callbacks) if reverse else self.callbacks\n        for c in callbacks:\n            try:\n                getattr(c, function_name)(**kwargs)\n            except Exception as e:\n                warnings.warn(\n                    f\"Callback {type(c).__name__}.{function_name} raised {type(e).__name__}: {e}\"\n                )\n\n    def on_run_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_run_start\", config=config, **kwargs)\n\n    def on_run_end(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_run_end\", config=config, reverse=True, **kwargs)\n\n    def on_multirun_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_multirun_start\", config=config, **kwargs)\n\n    def on_multirun_end(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(\n            function_name=\"on_multirun_end\", reverse=True, config=config, **kwargs\n        )\n\n    def on_job_start(self, config: DictConfig, **kwargs: Any) -> None:\n        self._notify(function_name=\"on_job_start\", config=config, **kwargs)\n\n    def on_job_end(\n        self, config: DictConfig, job_return: JobReturn, **kwargs: Any\n    ) -> None:\n        self._notify(\n            function_name=\"on_job_end\",\n            config=config,\n            job_return=job_return,\n            reverse=True,\n            **kwargs,\n        )\n", "path": "hydra/core/callbacks.py"}]}