Merge remote-tracking branch 'origin/netcore/netcore' into netcore/netcore

This commit is contained in:
Bjarke Berg
2020-08-24 14:16:04 +02:00
6 changed files with 62 additions and 46 deletions

View File

@@ -86,7 +86,7 @@ namespace Umbraco.Examine
|| !validator.ValidateProtectedContent(path, v.Category))
? 0
: 1;
});
}).ToList();
var hasDeletes = false;
var hasUpdates = false;
@@ -105,7 +105,7 @@ namespace Umbraco.Examine
{
hasUpdates = true;
//these are the valid ones, so just index them all at once
base.PerformIndexItems(group, onComplete);
base.PerformIndexItems(group.ToList(), onComplete);
}
}

View File

@@ -583,6 +583,26 @@ namespace Umbraco.Web.Search
public static void Execute(ExamineComponent examineComponent, IContent content, bool isPublished)
{
// TODO: This is ugly, it is going to build the value set 3x and for 2 of those times it will be the same value
// set. We can do better.
// TODO: We are .ToList() ing each of the calls to GetValueSets here. This is currently required but isn't the way
// that this was intended to work. Ideally, the IEnumerable package gets passed to Examine and it is only iterated/executed
// when the indexing takes place which would occur on a background thread. This is problematic with how the ContentValueSetBuilder
// in combination with UmbracoContentIndex.PerformIndexItems works because (at least what I've come to believe) we are using yield
// return in the GetValueSets call in combination with trying to lazily resolve the enumerable but because we GroupBy in
// UmbracoContentIndex.PerformIndexItems it's eagerly executed but then lazily executed again on the background thread and I believe
// that in doing this when the call is made to _userService.GetProfilesById it's trying to resolve a scope from an AsyncLocal instance
// that has already been disposed higher up it's chain. I 'think' to how the eager/lazy enumeration happens with yield return that it's
// capturing a scope/AsyncLocal instance that it shouldn't really be using.
// TODO: We don't want these value sets to be eagerly built in this thread since this is most likely going to be a request thread.
// This is why the lazy execution of the Enumerable had the intended affect of executing only when requested on the background thread.
// This could still be acheived: Either we have a custom Enumerable/Enumerator to do this, or we simply call the below code
// on a background thread... which would be much easier!
// TODO: I think this is an issue in v8 too!
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
//filter the indexers
.Where(x => isPublished || !x.PublishedValuesOnly)
@@ -593,7 +613,7 @@ namespace Umbraco.Web.Search
? examineComponent._publishedContentValueSetBuilder
: (IValueSetBuilder<IContent>)examineComponent._contentValueSetBuilder;
index.IndexItems(builder.GetValueSets(content));
index.IndexItems(builder.GetValueSets(content).ToList());
}
}
}

View File

@@ -3,10 +3,10 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -16,7 +16,6 @@ using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Scoping;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Services.Implement
{
@@ -29,15 +28,17 @@ namespace Umbraco.Core.Services.Implement
private readonly INotificationsRepository _notificationsRepository;
private readonly IGlobalSettings _globalSettings;
private readonly IContentSettings _contentSettings;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly IIOHelper _ioHelper;
public NotificationService(IScopeProvider provider, IUserService userService, IContentService contentService, ILocalizationService localizationService,
ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSettings contentSettings)
ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IGlobalSettings globalSettings, IContentSettings contentSettings, IEmailSender emailSender)
{
_notificationsRepository = notificationsRepository;
_globalSettings = globalSettings;
_contentSettings = contentSettings;
_emailSender = emailSender;
_uowProvider = provider ?? throw new ArgumentNullException(nameof(provider));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
@@ -405,8 +406,9 @@ namespace Umbraco.Core.Services.Implement
string.Concat(siteUri.Authority, _ioHelper.ResolveUrl(_globalSettings.UmbracoPath)),
summary.ToString());
var fromMail = _contentSettings.NotificationEmailAddress ?? _globalSettings.SmtpSettings.From;
// create the mail message
var mail = new MailMessage(_contentSettings.NotificationEmailAddress, mailingUser.Email);
var mail = new MailMessage(fromMail, mailingUser.Email);
// populate the message
@@ -508,51 +510,38 @@ namespace Umbraco.Core.Services.Implement
{
ThreadPool.QueueUserWorkItem(state =>
{
var s = new SmtpClient();
try
_logger.Debug<NotificationService>("Begin processing notifications.");
while (true)
{
_logger.Debug<NotificationService>("Begin processing notifications.");
while (true)
NotificationRequest request;
while (notificationRequests.TryTake(out request, 8 * 1000)) // stay on for 8s
{
NotificationRequest request;
while (notificationRequests.TryTake(out request, 8 * 1000)) // stay on for 8s
try
{
try
{
if (Sendmail != null) Sendmail(s, request.Mail, _logger); else s.Send(request.Mail);
_logger.Debug<NotificationService>("Notification '{Action}' sent to {Username} ({Email})", request.Action, request.UserName, request.Email);
}
catch (Exception ex)
{
_logger.Error<NotificationService>(ex, "An error occurred sending notification");
s.Dispose();
s = new SmtpClient();
}
finally
{
request.Mail.Dispose();
}
_emailSender.SendAsync(request.Mail).GetAwaiter().GetResult();
_logger.Debug<NotificationService>("Notification '{Action}' sent to {Username} ({Email})", request.Action, request.UserName, request.Email);
}
lock (Locker)
catch (Exception ex)
{
if (notificationRequests.Count > 0) continue; // last chance
_running = false; // going down
break;
_logger.Error<NotificationService>(ex, "An error occurred sending notification");
}
finally
{
request.Mail.Dispose();
}
}
lock (Locker)
{
if (notificationRequests.Count > 0) continue; // last chance
_running = false; // going down
break;
}
}
finally
{
s.Dispose();
}
_logger.Debug<NotificationService>("Done processing notifications.");
});
}
// for tests
internal static Action<SmtpClient, MailMessage, ILogger> Sendmail;
//= (_, msg, logger) => logger.Debug<NotificationService>("Email " + msg.To.ToString());
#endregion
}
}

View File

@@ -63,6 +63,13 @@ namespace Umbraco.Core.Sync
_lastPruned = _lastSync = DateTime.UtcNow;
_syncIdle = new ManualResetEvent(true);
_distCacheFilePath = new Lazy<string>(() => GetDistCacheFilePath(hostingEnvironment));
// See notes on LocalIdentity
LocalIdentity = NetworkHelper.MachineName // eg DOMAIN\SERVER
+ "/" + _hostingEnvironment.ApplicationId // eg /LM/S3SVC/11/ROOT
+ " [P" + Process.GetCurrentProcess().Id // eg 1234
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
+ "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique
}
protected ILogger Logger { get; }
@@ -526,11 +533,7 @@ namespace Umbraco.Core.Sync
/// <para>Practically, all we really need is the guid, the other infos are here for information
/// and debugging purposes.</para>
/// </remarks>
protected string LocalIdentity => NetworkHelper.MachineName // eg DOMAIN\SERVER
+ "/" + _hostingEnvironment.ApplicationId // eg /LM/S3SVC/11/ROOT
+ " [P" + Process.GetCurrentProcess().Id // eg 1234
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
+ "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique
protected string LocalIdentity { get; }
private string GetDistCacheFilePath(IHostingEnvironment hostingEnvironment)
{

View File

@@ -42,6 +42,8 @@ namespace Umbraco.Tests.TestHelpers
public static class TestHelper
{
private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal();
private static IEmailSender _emailSender;
private class TestHelperInternal : TestHelperBase
{
public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly)
@@ -103,6 +105,8 @@ namespace Umbraco.Tests.TestHelpers
public static IWebRoutingSettings WebRoutingSettings => _testHelperInternal.WebRoutingSettings;
public static IEmailSender EmailSender { get; } = new EmailSender(SettingsForTests.GenerateMockGlobalSettings());
/// <summary>
/// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name

View File

@@ -161,7 +161,7 @@ namespace Umbraco.Tests.TestHelpers
var dataTypeService = GetLazyService<IDataTypeService>(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDataTypeRepository>(c), GetRepo<IDataTypeContainerRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<IEntityRepository>(c), GetRepo<IContentTypeRepository>(c), ioHelper, localizedTextService.Value, localizationService.Value, TestHelper.ShortStringHelper));
var propertyValidationService = new Lazy<IPropertyValidationService>(() => new PropertyValidationService(propertyEditorCollection, dataTypeService.Value, localizedTextService.Value));
var contentService = GetLazyService<IContentService>(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo<IDocumentRepository>(c), GetRepo<IEntityRepository>(c), GetRepo<IAuditRepository>(c), GetRepo<IContentTypeRepository>(c), GetRepo<IDocumentBlueprintRepository>(c), GetRepo<ILanguageRepository>(c), propertyValidationService, TestHelper.ShortStringHelper));
var notificationService = GetLazyService<INotificationService>(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo<INotificationsRepository>(c), globalSettings, contentSettings));
var notificationService = GetLazyService<INotificationService>(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo<INotificationsRepository>(c), globalSettings, contentSettings, TestHelper.EmailSender));
var serverRegistrationService = GetLazyService<IServerRegistrationService>(factory, c => new ServerRegistrationService(scopeProvider, logger, eventMessagesFactory, GetRepo<IServerRegistrationRepository>(c), TestHelper.GetHostingEnvironment()));
var memberGroupService = GetLazyService<IMemberGroupService>(factory, c => new MemberGroupService(scopeProvider, logger, eventMessagesFactory, GetRepo<IMemberGroupRepository>(c)));
var memberService = GetLazyService<IMemberService>(factory, c => new MemberService(scopeProvider, logger, eventMessagesFactory, memberGroupService.Value, GetRepo<IMemberRepository>(c), GetRepo<IMemberTypeRepository>(c), GetRepo<IMemberGroupRepository>(c), GetRepo<IAuditRepository>(c)));