Skip to content

Commit 075ebcc

Browse files
authored
Merge pull request #754 from statisticssweden/feature/AddLoggingToCreationOfBulkFiles
Improve logging and error handling in BulkService
2 parents 45ff701 + 0cba96b commit 075ebcc

File tree

4 files changed

+108
-34
lines changed

4 files changed

+108
-34
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
- Improve logging and error handling in BulkService. Upgrade library dependencies (System.Buffers, System.Memory, etc.) to newer versions
12
- Updated assembly binding versions in template web.config
23
- Misc upgrade of dependencies
34
- Fix for problems to show result if multiple contents is choosen. #675

PXWeb/Code/API/Services/BulkService.cs

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using PXWeb.Management;
66
using System;
77
using System.Collections.Generic;
8+
using System.Diagnostics;
89
using System.IO;
910
using System.IO.Compression;
1011
using System.Linq;
@@ -17,7 +18,11 @@ public class BulkService : IBulkService
1718
{
1819
private readonly IBulkRegistry _registry;
1920
private readonly ITableService _tableService;
20-
private readonly log4net.ILog _logger;
21+
private readonly log4net.ILog _logger;
22+
23+
// Added: progress logging controls
24+
private const int ProgressLogInterval = 50; // tables
25+
private static readonly TimeSpan ProgressTimeInterval = TimeSpan.FromSeconds(30); // max time between progress logs
2126

2227
/// <summary>
2328
/// Initializes a new instance of the <see cref="BulkService"/> class.
@@ -28,6 +33,7 @@ public BulkService(IBulkRegistry registry, ITableService tableService)
2833
{
2934
_registry = registry;
3035
_tableService = tableService;
36+
_logger = log4net.LogManager.GetLogger(typeof(BulkService));
3137
}
3238

3339
/// <summary>
@@ -52,14 +58,15 @@ public bool CreateBulkFilesForDatabase(string database)
5258
var tables = GetTablesForLanguage(database, language);
5359
if (tables == null || !tables.Any())
5460
{
61+
_logger.Warn($"No tables found for {database}/{language}.");
5562
continue;
5663
}
5764

5865
var dbPath = GetDatabasePath(database, language);
5966
var tempPath = Path.Combine(dbPath, "temp");
6067

6168
InitDatabaseFolder(dbPath, tempPath);
62-
_registry.SetContext(dbPath,language);
69+
_registry.SetContext(dbPath, language);
6370

6471
ProcessTables(database, language, tables, tempPath, dbPath);
6572
}
@@ -101,43 +108,109 @@ private string GetDatabasePath(string database, string language)
101108
private void ProcessTables(string database, string language, List<TableLink> tables, string tempPath, string dbPath)
102109
{
103110
var serializer = new PCAxis.Paxiom.Csv2FileSerializer();
104-
105111
#if DEBUG
106112
if (tables.Count > 10)
107113
{
108114
tables = tables.Take(10).ToList();
109115
}
110116
#endif
117+
int total = tables.Count;
118+
int processed = 0;
119+
int updated = 0;
120+
int skippedUnchanged = 0;
121+
int skippedNullModel = 0;
122+
int errors = 0;
123+
var overall = Stopwatch.StartNew();
124+
var progressTimer = Stopwatch.StartNew();
125+
_logger.Info($"Bulk start {database}/{language}. Tables to process: {total}");
111126

112127
foreach (var table in tables)
113128
{
114-
if (!_registry.ShouldTableBeUpdated(table.TableId, table.Published.Value))
129+
processed++;
130+
try
115131
{
116-
continue;
117-
}
132+
if (!_registry.ShouldTableBeUpdated(table.TableId, table.Published.Value))
133+
{
134+
skippedUnchanged++;
135+
}
136+
else
137+
{
138+
var model = _tableService.GetTableModel(database, table.ID.Selection, language);
139+
if (model == null)
140+
{
141+
skippedNullModel++;
142+
}
143+
else
144+
{
145+
var csvPath = Path.Combine(tempPath, $"{table.TableId}_{language}.csv");
146+
serializer.Serialize(model, csvPath);
118147

119-
var model = _tableService.GetTableModel(database, table.ID.Selection, language);
120-
if (model == null)
121-
{
122-
continue;
123-
}
148+
var zipPath = Path.Combine(dbPath, $"{table.TableId}_{language}.zip");
149+
if (File.Exists(zipPath))
150+
{
151+
File.Delete(zipPath);
152+
}
124153

125-
var csvPath = Path.Combine(tempPath, $"{table.TableId}_{language}.csv");
126-
serializer.Serialize(model, csvPath);
154+
ZipFile.CreateFromDirectory(tempPath, zipPath);
155+
File.Delete(csvPath);
127156

128-
var zipPath = Path.Combine(dbPath, $"{table.TableId}_{language}.zip");
129-
if (File.Exists(zipPath))
157+
_registry.RegisterTableBulkFileUpdated(table.TableId, table.Text, DateTime.Now);
158+
updated++;
159+
}
160+
}
161+
}
162+
catch (Exception ex)
130163
{
131-
File.Delete(zipPath);
164+
errors++;
165+
_logger.Error($"Error generating bulk file for table {table.TableId} ({processed}/{total}) i {database}/{language}: {ex.Message}", ex);
132166
}
133167

134-
ZipFile.CreateFromDirectory(tempPath, zipPath);
135-
File.Delete(csvPath);
136-
137-
_registry.RegisterTableBulkFileUpdated(table.TableId, table.Text, DateTime.Now);
168+
// Progress logging (count or time based)
169+
if (_logger.IsInfoEnabled && (processed % ProgressLogInterval == 0 || progressTimer.Elapsed > ProgressTimeInterval))
170+
{
171+
long managedMem = GC.GetTotalMemory(false) / (1024 * 1024); // MB
172+
long procMem = 0;
173+
try
174+
{
175+
procMem = Process.GetCurrentProcess().PrivateMemorySize64 / (1024 * 1024); // MB
176+
}
177+
catch (Exception ex)
178+
{
179+
_logger.Warn("Failed to get process memory usage", ex);
180+
}
181+
int tempFileCount = 0;
182+
try
183+
{
184+
tempFileCount = Directory.Exists(tempPath) ? Directory.GetFiles(tempPath).Length : 0;
185+
}
186+
catch (Exception ex)
187+
{
188+
_logger.Warn($"Failed to count temp files in {tempPath}", ex);
189+
}
190+
_logger.Info($"Progress {database}/{language}: {processed}/{total}. Updated: {updated}, Unchanged: {skippedUnchanged}, NullModel: {skippedNullModel}, Errors: {errors}. ManagedMem(MB): {managedMem}, ProcMem(MB): {procMem}, TempFiles: {tempFileCount}. Elapsed: {overall.Elapsed}.");
191+
progressTimer.Restart();
192+
}
138193
}
139194

140-
_registry.Save();
195+
// Log before Save
196+
_logger.Info($"Saving registry for {database}/{language}...");
197+
try
198+
{
199+
_registry.Save();
200+
_logger.Info($"Registry saved for {database}/{language}.");
201+
}
202+
catch (Exception ex)
203+
{
204+
_logger.Error($"Error during Save() for {database}/{language}: {ex.Message}", ex);
205+
}
206+
try
207+
{
208+
_logger.Info($"Bulk complete {database}/{language}. Totalt: {total}, Updated: {updated}, Unchanged: {skippedUnchanged}, NullModel: {skippedNullModel}, Errors: {errors}. Total time: {overall.Elapsed}");
209+
}
210+
catch (Exception ex)
211+
{
212+
_logger.Error($"Error during final logging for {database}/{language}: {ex.Message}", ex);
213+
}
141214
}
142215

143216
/// <summary>
@@ -184,7 +257,7 @@ private void InitDatabaseFolder(string dbPath, string tempPath)
184257
}
185258
}
186259
}
187-
}
260+
}
188261

189262
}
190263

PXWeb/PXWeb.csproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@
180180
<HintPath>..\packages\SixLabors.Fonts.1.0.0\lib\netstandard2.0\SixLabors.Fonts.dll</HintPath>
181181
</Reference>
182182
<Reference Include="System" />
183-
<Reference Include="System.Buffers, Version=4.0.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
184-
<HintPath>..\packages\System.Buffers.4.6.0\lib\net462\System.Buffers.dll</HintPath>
183+
<Reference Include="System.Buffers, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
184+
<HintPath>..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll</HintPath>
185185
</Reference>
186186
<Reference Include="System.ClientModel, Version=1.6.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
187187
<HintPath>..\packages\System.ClientModel.1.6.0\lib\netstandard2.0\System.ClientModel.dll</HintPath>
@@ -227,8 +227,8 @@
227227
<Reference Include="System.IO.Packaging, Version=8.0.0.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
228228
<HintPath>..\packages\System.IO.Packaging.8.0.1\lib\net462\System.IO.Packaging.dll</HintPath>
229229
</Reference>
230-
<Reference Include="System.Memory, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
231-
<HintPath>..\packages\System.Memory.4.6.0\lib\net462\System.Memory.dll</HintPath>
230+
<Reference Include="System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
231+
<HintPath>..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll</HintPath>
232232
</Reference>
233233
<Reference Include="System.Memory.Data, Version=8.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
234234
<HintPath>..\packages\System.Memory.Data.8.0.1\lib\net462\System.Memory.Data.dll</HintPath>
@@ -243,17 +243,17 @@
243243
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.6.0.0\lib\net45\System.Net.Http.Formatting.dll</HintPath>
244244
</Reference>
245245
<Reference Include="System.Numerics" />
246-
<Reference Include="System.Numerics.Vectors, Version=4.1.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
247-
<HintPath>..\packages\System.Numerics.Vectors.4.6.0\lib\net462\System.Numerics.Vectors.dll</HintPath>
246+
<Reference Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
247+
<HintPath>..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll</HintPath>
248248
</Reference>
249249
<Reference Include="System.Runtime, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
250250
<HintPath>..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll</HintPath>
251251
<Private>True</Private>
252252
<Private>True</Private>
253253
</Reference>
254254
<Reference Include="System.Runtime.Caching" />
255-
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
256-
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.1.0\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
255+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
256+
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
257257
</Reference>
258258
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
259259
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>

PXWeb/packages.config

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<package id="PXWeb.SavedQuery.MsSql" version="1.0.5" targetFramework="net48" />
4848
<package id="PXWeb.SavedQuery.Oracle" version="1.0.7" targetFramework="net48" />
4949
<package id="SixLabors.Fonts" version="1.0.0" targetFramework="net48" />
50-
<package id="System.Buffers" version="4.6.0" targetFramework="net48" />
50+
<package id="System.Buffers" version="4.6.1" targetFramework="net48" />
5151
<package id="System.ClientModel" version="1.6.0" targetFramework="net48" />
5252
<package id="System.Configuration.ConfigurationManager" version="8.0.1" targetFramework="net48" />
5353
<package id="System.Data.Common" version="4.3.0" targetFramework="net48" />
@@ -60,14 +60,14 @@
6060
<package id="System.IO.FileSystem.AccessControl" version="5.0.0" targetFramework="net48" />
6161
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net48" />
6262
<package id="System.IO.Packaging" version="8.0.1" targetFramework="net48" />
63-
<package id="System.Memory" version="4.6.0" targetFramework="net48" />
63+
<package id="System.Memory" version="4.6.3" targetFramework="net48" />
6464
<package id="System.Memory.Data" version="8.0.1" targetFramework="net48" />
6565
<package id="System.Net.Http" version="4.3.4" targetFramework="net48" />
66-
<package id="System.Numerics.Vectors" version="4.6.0" targetFramework="net48" />
66+
<package id="System.Numerics.Vectors" version="4.6.1" targetFramework="net48" />
6767
<package id="System.Reflection.Emit.ILGeneration" version="4.7.0" targetFramework="net48" />
6868
<package id="System.Reflection.Emit.Lightweight" version="4.7.0" targetFramework="net48" />
6969
<package id="System.Runtime" version="4.3.1" targetFramework="net48" />
70-
<package id="System.Runtime.CompilerServices.Unsafe" version="6.1.0" targetFramework="net48" />
70+
<package id="System.Runtime.CompilerServices.Unsafe" version="6.1.2" targetFramework="net48" />
7171
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net48" />
7272
<package id="System.Security.AccessControl" version="6.0.1" targetFramework="net48" />
7373
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net48" />

0 commit comments

Comments
 (0)