We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Datasources stuck in sync when using git + ssh from ./manage.py syncdatasource
### NetBox version

v3.6.1

### Python version

3.11

### Steps to Reproduce

In Data Sources
Add
Name: test
Type: git
URL: git@github.com:netbox-community/netbox.git
Create

docker compose exec netbox ./manage.py syncdatasource test





### Expected Behavior

Usually leads to some sort of ssh question or failure, and I would expect the exception to set the status to failed, and then be able to hit sync again.

I'm not sure exactly how NetBox works, but looking at one of the exceptions...
core.exceptions.SyncError: Fetching remote data failed (HangupException): 

class SyncError(Exception):
    pass

Does this mean the status is not being reset correctly due to the status being left as syncing?



### Observed Behavior

datasource.status = syncing in nbshell
'syncing' in gui
Sync option is now greyed out and cannot reset status without manually setting it in nbshell:

for d in DataSource.objects.filter(status='syncing'):
  d.status = 'failed'
  d.save()


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netbox/core/management/commands/syncdatasource.py`
Content:
```
1 from django.core.management.base import BaseCommand, CommandError
2 
3 from core.models import DataSource
4 
5 
6 class Command(BaseCommand):
7     help = "Synchronize a data source from its remote upstream"
8 
9     def add_arguments(self, parser):
10         parser.add_argument('name', nargs='*', help="Data source(s) to synchronize")
11         parser.add_argument(
12             "--all", action='store_true', dest='sync_all',
13             help="Synchronize all data sources"
14         )
15 
16     def handle(self, *args, **options):
17 
18         # Find DataSources to sync
19         if options['sync_all']:
20             datasources = DataSource.objects.all()
21         elif options['name']:
22             datasources = DataSource.objects.filter(name__in=options['name'])
23             # Check for invalid names
24             found_names = {ds['name'] for ds in datasources.values('name')}
25             if invalid_names := set(options['name']) - found_names:
26                 raise CommandError(f"Invalid data source names: {', '.join(invalid_names)}")
27         else:
28             raise CommandError(f"Must specify at least one data source, or set --all.")
29 
30         if len(options['name']) > 1:
31             self.stdout.write(f"Syncing {len(datasources)} data sources.")
32 
33         for i, datasource in enumerate(datasources, start=1):
34             self.stdout.write(f"[{i}] Syncing {datasource}... ", ending='')
35             self.stdout.flush()
36             datasource.sync()
37             self.stdout.write(datasource.get_status_display())
38             self.stdout.flush()
39 
40         if len(options['name']) > 1:
41             self.stdout.write(f"Finished.")
42
```
--- 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/netbox/core/management/commands/syncdatasource.py b/netbox/core/management/commands/syncdatasource.py
--- a/netbox/core/management/commands/syncdatasource.py
+++ b/netbox/core/management/commands/syncdatasource.py
@@ -1,5 +1,6 @@
 from django.core.management.base import BaseCommand, CommandError
 
+from core.choices import DataSourceStatusChoices
 from core.models import DataSource
 
 
@@ -33,9 +34,13 @@
         for i, datasource in enumerate(datasources, start=1):
             self.stdout.write(f"[{i}] Syncing {datasource}... ", ending='')
             self.stdout.flush()
-            datasource.sync()
-            self.stdout.write(datasource.get_status_display())
-            self.stdout.flush()
+            try:
+                datasource.sync()
+                self.stdout.write(datasource.get_status_display())
+                self.stdout.flush()
+            except Exception as e:
+                DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED)
+                raise e
 
         if len(options['name']) > 1:
             self.stdout.write(f"Finished.")

{"golden_diff": "diff --git a/netbox/core/management/commands/syncdatasource.py b/netbox/core/management/commands/syncdatasource.py\n--- a/netbox/core/management/commands/syncdatasource.py\n+++ b/netbox/core/management/commands/syncdatasource.py\n@@ -1,5 +1,6 @@\n from django.core.management.base import BaseCommand, CommandError\n \n+from core.choices import DataSourceStatusChoices\n from core.models import DataSource\n \n \n@@ -33,9 +34,13 @@\n         for i, datasource in enumerate(datasources, start=1):\n             self.stdout.write(f\"[{i}] Syncing {datasource}... \", ending='')\n             self.stdout.flush()\n-            datasource.sync()\n-            self.stdout.write(datasource.get_status_display())\n-            self.stdout.flush()\n+            try:\n+                datasource.sync()\n+                self.stdout.write(datasource.get_status_display())\n+                self.stdout.flush()\n+            except Exception as e:\n+                DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED)\n+                raise e\n \n         if len(options['name']) > 1:\n             self.stdout.write(f\"Finished.\")\n", "issue": "Datasources stuck in sync when using git + ssh from ./manage.py syncdatasource\n### NetBox version\n\nv3.6.1\n\n### Python version\n\n3.11\n\n### Steps to Reproduce\n\nIn Data Sources\r\nAdd\r\nName: test\r\nType: git\r\nURL: git@github.com:netbox-community/netbox.git\r\nCreate\r\n\r\ndocker compose exec netbox ./manage.py syncdatasource test\r\n\r\n\r\n\r\n\n\n### Expected Behavior\n\nUsually leads to some sort of ssh question or failure, and I would expect the exception to set the status to failed, and then be able to hit sync again.\r\n\r\nI'm not sure exactly how NetBox works, but looking at one of the exceptions...\r\ncore.exceptions.SyncError: Fetching remote data failed (HangupException): \r\n\r\nclass SyncError(Exception):\r\n    pass\r\n\r\nDoes this mean the status is not being reset correctly due to the status being left as syncing?\r\n\r\n\n\n### Observed Behavior\n\ndatasource.status = syncing in nbshell\r\n'syncing' in gui\r\nSync option is now greyed out and cannot reset status without manually setting it in nbshell:\r\n\r\nfor d in DataSource.objects.filter(status='syncing'):\r\n  d.status = 'failed'\r\n  d.save()\r\n\n", "before_files": [{"content": "from django.core.management.base import BaseCommand, CommandError\n\nfrom core.models import DataSource\n\n\nclass Command(BaseCommand):\n    help = \"Synchronize a data source from its remote upstream\"\n\n    def add_arguments(self, parser):\n        parser.add_argument('name', nargs='*', help=\"Data source(s) to synchronize\")\n        parser.add_argument(\n            \"--all\", action='store_true', dest='sync_all',\n            help=\"Synchronize all data sources\"\n        )\n\n    def handle(self, *args, **options):\n\n        # Find DataSources to sync\n        if options['sync_all']:\n            datasources = DataSource.objects.all()\n        elif options['name']:\n            datasources = DataSource.objects.filter(name__in=options['name'])\n            # Check for invalid names\n            found_names = {ds['name'] for ds in datasources.values('name')}\n            if invalid_names := set(options['name']) - found_names:\n                raise CommandError(f\"Invalid data source names: {', '.join(invalid_names)}\")\n        else:\n            raise CommandError(f\"Must specify at least one data source, or set --all.\")\n\n        if len(options['name']) > 1:\n            self.stdout.write(f\"Syncing {len(datasources)} data sources.\")\n\n        for i, datasource in enumerate(datasources, start=1):\n            self.stdout.write(f\"[{i}] Syncing {datasource}... \", ending='')\n            self.stdout.flush()\n            datasource.sync()\n            self.stdout.write(datasource.get_status_display())\n            self.stdout.flush()\n\n        if len(options['name']) > 1:\n            self.stdout.write(f\"Finished.\")\n", "path": "netbox/core/management/commands/syncdatasource.py"}], "after_files": [{"content": "from django.core.management.base import BaseCommand, CommandError\n\nfrom core.choices import DataSourceStatusChoices\nfrom core.models import DataSource\n\n\nclass Command(BaseCommand):\n    help = \"Synchronize a data source from its remote upstream\"\n\n    def add_arguments(self, parser):\n        parser.add_argument('name', nargs='*', help=\"Data source(s) to synchronize\")\n        parser.add_argument(\n            \"--all\", action='store_true', dest='sync_all',\n            help=\"Synchronize all data sources\"\n        )\n\n    def handle(self, *args, **options):\n\n        # Find DataSources to sync\n        if options['sync_all']:\n            datasources = DataSource.objects.all()\n        elif options['name']:\n            datasources = DataSource.objects.filter(name__in=options['name'])\n            # Check for invalid names\n            found_names = {ds['name'] for ds in datasources.values('name')}\n            if invalid_names := set(options['name']) - found_names:\n                raise CommandError(f\"Invalid data source names: {', '.join(invalid_names)}\")\n        else:\n            raise CommandError(f\"Must specify at least one data source, or set --all.\")\n\n        if len(options['name']) > 1:\n            self.stdout.write(f\"Syncing {len(datasources)} data sources.\")\n\n        for i, datasource in enumerate(datasources, start=1):\n            self.stdout.write(f\"[{i}] Syncing {datasource}... \", ending='')\n            self.stdout.flush()\n            try:\n                datasource.sync()\n                self.stdout.write(datasource.get_status_display())\n                self.stdout.flush()\n            except Exception as e:\n                DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED)\n                raise e\n\n        if len(options['name']) > 1:\n            self.stdout.write(f\"Finished.\")\n", "path": "netbox/core/management/commands/syncdatasource.py"}]}