Мне трудно разобраться с этим, может быть, кто-то может мне здесь помочь.
У меня есть веб-приложение Asp.net Core 2.0, я использую Hangfire для обработки заданий в фоновом режиме.обычно это синхронизирует продукты или заказы между различными платформами, но есть одно задание, которое всегда терпит неудачу с «Недостаточно памяти для продолжения выполнения программы».а также 'Ссылка на объект не установлена для экземпляра объекта', я записываю трассировку, и она приводит меня к Parallel.ForEach, где выдается ошибка, теперь, когда я делаю то же самое вручную (имеется в виду без зависания), я не получаюисключение и все работает просто отлично.
, поэтому позвольте мне поделиться здесь некоторым кодом.
, поэтому сначала мы настроим Hangfire следующим образомвнутри класса запуска, в методе Configure, мы делаем это.
app.UseHangfireDashboard("/tasks", new DashboardOptions() {
Authorization = new[] { new HangFireAuthorizationFilter() }
});
var schedules = new ScheduleTasks(app.ApplicationServices);
schedules.RegisterRecurentJobs();
Теперь ScheduleTasks выглядит следующим образом.
public class ScheduleTasks
{
private readonly IApiService _apiService;
private readonly ISettingService _settingService;
public ScheduleTasks(IServiceProvider serviceProvider)
{
var scope = serviceProvider.CreateScope();
_apiService = scope.ServiceProvider.GetService<IApiService>();
_settingService = scope.ServiceProvider.GetService<ISettingService>();
}
public void RegisterRecurentJobs()
{
var settings = _settingService.LoadSetting<ApiSettings>();
if(!settings.SilentMode)
{
RecurringJob.AddOrUpdate<IApiService>("Config", x => x.SyncConfig(), "* 1 * * *");
RecurringJob.AddOrUpdate<IApiService>("Manufacturers", x => x.SyncManufacturers(), "* 2 * * *");
RecurringJob.AddOrUpdate<IApiService>("Products", x => x.SyncProducts(30, false), "* 3 * * *");
}
}
}
и вот мой сервисный метод API, который выполнилSyncProducts.
public async Task SyncProducts(int days, bool hasSalesOnly = true)
{
var s = new StringBuilder();
try
{
var search = new SearchModel()
{
ModifiedDate = new DateRange()
{
FromDate = DateTime.Today.AddDays(-days)
},
PageSize = 300000,
HaveSalesOnly = hasSalesOnly
};
var ids = await _productService.GetProductFeed(search);
var hasNext = ids?.Result?.AdditionalResultsId;
var failedIds = new List<string>();
var retry = true;
while (ids.Result.Ids != null && ids.Result.Ids.Count > 0)
{
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 20 };
s.Append("[");
var start = true;
Parallel.ForEach(ids.Result.Ids, parallelOptions, id =>
{
var itemResult = _productService.GetProductByProductId(id).Result;
if (itemResult.Success)
{
lock (s)
{
if (start)
{
s.Append(itemResult.ResponseString);
}
else
{
var r = "," + itemResult.ResponseString;
s.Append(r);
}
start = false;
}
}
else
{
failedIds.Add(id);
}
itemResult = null;
});
s.Append("]");
var newFileName = "result.json";
var newFileDir = GetJsonFileDirectoryPath() + newFileName;
var baseDir = Environment.CurrentDirectory + "/wwwroot";
var dataPath = baseDir + newFileDir;
File.WriteAllText(dataPath, s.ToString());
s = null;
ids.Result.Ids = null;
var param = new SqlParameter
{
ParameterName = "path",
SqlDbType = SqlDbType.VarChar,
Direction = ParameterDirection.Input,
Value = dataPath
};
var imagesToProcess = await _itemRepository.ExecuteStoredProcedureList<SyncItems>("[dbo].[SyncItems]", param);
foreach (var image in imagesToProcess)
{
if (image.ProductId == null)
continue;
//for now delete all images, and save the new ones.
var imagesToDelete = _pictureService.GetProductPicturesByProductId(image.ProductId.Value);
foreach (var i in imagesToDelete)
{
await _pictureService.DeleteProductPicture(i);
}
if (image.ImageUrls != null)
{
var imageList = image.ImageUrls.Split(',');
foreach (var i in imageList)
{
await _pictureService.InsertProductPictureFromPictureUrl(i, image.ProductId.Value);
}
}
}
if (!string.IsNullOrEmpty(hasNext))
{
ids = await _productService.GetNextPage(ids.Result.AdditionalResultsId);
hasNext = ids.Result.AdditionalResultsId;
}
else
{
ids.Result.Ids = null;
}
if (string.IsNullOrEmpty(hasNext) && ids.Result.Ids == null && retry ||
string.IsNullOrEmpty(hasNext) && ids.Result.Ids.Count == 0 && retry)
{
ids = new BaseSearchResult();
ids.Result.Ids = failedIds;
failedIds = new List<string>();
retry = false;
}
}
ids = null;
}
catch (Exception ex)
{
s = null;
aEvent = new ApiEvent()
{
Level = LogLevel.Critical,
EventDate = DateTime.Now,
User = "Api",
EventType = EventTypeEnum.Product,
EntityTypeId = "",
Event = ex.Message,
Details = ex.StackTrace
};
await _eventService.PublishEvent(aEvent);
}
}
Если я выполняю этот метод вручную, либо путем написания функционального теста для выполнения метода, либо с помощью кнопки на моей странице, которая вызывает выполнение этого метода, все работает нормально, но когдаHangfire пытается выполнить точно такой же метод, я получаю эту ошибку.
Произошла одна или несколько ошибок.(Недостаточно памяти для продолжения выполнения программы.) (Ссылка на объект не установлена для экземпляра объекта.) (Ссылка на объект не установлена для экземпляра объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объектаobject.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляробъекта.) (Ссылка на объект не установлена для экземпляра объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена наэкземпляр объекта.) (Ссылка на объект не установлена на экземпляр объекта.) (Ссылка на объект не установлена на экземпляробъекта.) (Ссылка на объект не установлена для экземпляра объекта.)
и трассировка такова.
в System.Threading.Tasks.TaskReplicator.Run [TState] (ReplicatableUserAction 1 action, ParallelOptions options, Boolean stopOnFirstFailure)
at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action
1 body, Action 2 bodyWithState, Func
4 bodyWithLocal, Func 1 localInit, Action
1 localFinally) --- Конец трассировки стека из предыдущего расположения, в котором было сгенерировано исключение --- в System.Threading.TasksКласс, Список действий 1 localFinally)
at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IList
1, Параллельные параметры ParallelOptions, Действия 1 body, Action
2 bodyWithState, Действие 3 bodyWithStateAndIndex, Func
4 bodyWithStateAndLocal, Func 5 bodyWithEverything, Func
1 localInit, Источник действия 1 localFinally)
at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable
1, Параллельные параметры ParallelOptions, Действие 1 body, Action
2 bodyWithState, Действие3 bodyWithStateAndIndex, Func
4 bodyWithStateAndLocal, Func 5 bodyWithEverything, Func
1 localInit, Action 1 localFinally)
at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable
1 source, ParallelOptions parallelOptions, тело Action`1) в *****. *****. Services.ApiService.SyncProducts (Int32 дней, логическое значение hasSalesOnly) в C: ***************. **** \ Services \ ApiService.cs: строка 493
Может кто-нибудь помочь мне понять, почему происходит сбой при выполнении метода hangfire?
Заранее спасибо завсе смотрят на это.