diff --git a/uSync.BackOffice/Boot/FirstBootMigration.cs b/uSync.BackOffice/Boot/FirstBootMigration.cs
index ea582dbf3..a92097329 100644
--- a/uSync.BackOffice/Boot/FirstBootMigration.cs
+++ b/uSync.BackOffice/Boot/FirstBootMigration.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Threading.Tasks;
+using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Migrations;
@@ -30,9 +31,10 @@ public FirstBootMigrationPlan()
///
/// First boot Feature migration
///
-public class FirstBootMigration : AsyncMigrationBase
+public class FirstBootMigration : UnscopedAsyncMigrationBase
{
private readonly IUmbracoContextFactory _umbracoContextFactory;
+ private readonly IServerRoleAccessor _serverRoleAccessor;
private readonly ISyncConfigService _uSyncConfig;
private readonly ISyncService _uSyncService;
private readonly ILogger _logger;
@@ -43,19 +45,19 @@ public FirstBootMigration(
IUmbracoContextFactory umbracoContextFactory,
ISyncConfigService uSyncConfig,
ISyncService uSyncService,
- ILogger logger) : base(context)
+ ILogger logger,
+ IServerRoleAccessor serverRoleAccessor) : base(context)
{
_umbracoContextFactory = umbracoContextFactory;
_uSyncConfig = uSyncConfig;
_uSyncService = uSyncService;
_logger = logger;
+ _serverRoleAccessor = serverRoleAccessor;
}
///
protected override async Task MigrateAsync()
{
- // TODO: doesn't work in the betas. might need a new migration to add it.
- // return;
// first boot migration.
try
@@ -63,6 +65,12 @@ protected override async Task MigrateAsync()
if (!_uSyncConfig.Settings.ImportOnFirstBoot)
return;
+ if (_serverRoleAccessor.CurrentServerRole == ServerRole.Subscriber)
+ {
+ _logger.LogInformation("This is a Subscriber server in a load balanced setup - uSync only runs on single or schedulingPublisher (main) servers");
+ return;
+ }
+
var sw = Stopwatch.StartNew();
var changes = 0;
@@ -72,8 +80,9 @@ protected override async Task MigrateAsync()
// if config service is set to import on first boot then this
// will let uSync do a first boot import
- // not sure about context on migrations so will need to test
- // or maybe we fire something into a notification (or use a static)
+ // this runs as a 'un-scoped' migration, so we need to manage the context here.
+ // as we are in the context and not just a scope all the publish stuff works
+ // first time, just like it does in ImportOnStartup
using (var reference = _umbracoContextFactory.EnsureUmbracoContext())
{
@@ -92,7 +101,12 @@ protected override async Task MigrateAsync()
catch (Exception ex)
{
_logger.LogError(ex, "uSync First boot failed {message}", ex.Message);
- throw;
}
+ finally
+ {
+ // we always complete the context - even if we fail.
+ // we don't want to keep trying this migration every time.
+ Context.Complete();
+ }
}
}
diff --git a/uSync.BackOffice/Notifications/uSyncApplicationStartingHandler.cs b/uSync.BackOffice/Notifications/uSyncApplicationStartingHandler.cs
index 71f1e56a8..cda58590d 100644
--- a/uSync.BackOffice/Notifications/uSyncApplicationStartingHandler.cs
+++ b/uSync.BackOffice/Notifications/uSyncApplicationStartingHandler.cs
@@ -120,8 +120,8 @@ private async Task InituSyncAsync()
};
_logger.LogInformation("uSync: Running export at startup");
-
-
+
+
_uSyncService.StartupExportAsync(_uSyncConfig.GetWorkingFolder(), options).Wait();
}
@@ -131,10 +131,10 @@ private async Task InituSyncAsync()
if (!HasStopFile(_uSyncConfig.GetWorkingFolder()))
{
- _uSyncService.StartupImportAsync(_uSyncConfig.GetFolders(), false, new SyncHandlerOptions
+ await _uSyncService.StartupImportAsync(_uSyncConfig.GetFolders(), false, new SyncHandlerOptions
{
Group = _uSyncConfig.Settings.ImportAtStartup
- }).Wait();
+ });
await ProcessOnceFileAsync(_uSyncConfig.GetWorkingFolder());
}
diff --git a/uSync.BackOffice/Services/SyncService.cs b/uSync.BackOffice/Services/SyncService.cs
index 078b35ee5..0efa3a9d6 100644
--- a/uSync.BackOffice/Services/SyncService.cs
+++ b/uSync.BackOffice/Services/SyncService.cs
@@ -22,6 +22,7 @@
using uSync.BackOffice.SyncHandlers;
using uSync.BackOffice.SyncHandlers.Models;
using uSync.Core;
+using uSync.Core.Extensions;
using uSync.Core.Serialization;
namespace uSync.BackOffice;
@@ -113,9 +114,28 @@ public bool HasRootFiles(string[] folders)
#region Importing
static readonly SemaphoreSlim _importSemaphoreLock = new SemaphoreSlim(1, 1);
+ ///
+ /// hash of the options last used in a startup import
+ ///
+ ///
+ /// as both first boot and import at startup use this method,
+ /// and both can be triggered at startup, we use a hash of the
+ /// options and folders to make sure we are not running them
+ /// both if they are asking the same thing.
+ ///
+ static int? _lastStartupRun;
+
/// >
public async Task> StartupImportAsync(string[] folders, bool force, SyncHandlerOptions handlerOptions, uSyncCallbacks? callbacks = null)
{
+ var runHash = $"{string.Join(",", folders)}{force}{handlerOptions.SerializeJsonString(false)}".GetDeterministicHashCode();
+
+ if (_lastStartupRun.HasValue && _lastStartupRun.Value == runHash)
+ {
+ _logger.LogInformation("uSync: Skipping [duplicate] startup import has already ran with these parameters");
+ return [];
+ }
+
handlerOptions ??= new SyncHandlerOptions();
handlerOptions.Action = HandlerActions.Import;
var handlers = _handlerFactory.GetValidHandlers(handlerOptions);
@@ -127,6 +147,8 @@ public async Task> StartupImportAsync(string[] folders,
if (changes.Any(x => x.Change > ChangeType.NoChange && x.ItemType == "IContent"))
_distributedCache.RefreshAllPublishedSnapshot();
+ _lastStartupRun = runHash;
+
return changes;
}