프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

markus / ConvertService / ServiceBase / Markus.Service.Station / StationService / ServiceStationTask.cs @ 4b33593a

이력 | 보기 | 이력해설 | 다운로드 (22.8 KB)

1
using Markus.Message;
2
using System;
3
using System.Collections.Generic;
4
using System.Diagnostics;
5
using System.Linq;
6
using System.Text;
7
using System.Threading;
8
using System.Threading.Tasks;
9
using System.Management;
10
using static Markus.Service.Extensions.Encrypt;
11
using Markus.Service.Extensions;
12
using Markus.Service.Helper;
13
using Markus.Service.DataBase.Entities;
14
using Markus.Service.DataBase.Repositories;
15

    
16
namespace Markus.Service
17
{
18
    /// <summary>
19
    /// 컨버터 큐 처리 
20
    /// </summary>
21
    public partial class ServiceStation
22
    {
23
        /// <summary>
24
        /// 컨버터 실행중인 item
25
        /// </summary>
26
        private static List<ConvertDoc> AliveConvertQueue = new List<ConvertDoc>();
27

    
28
        /// <summary>
29
        /// 컨버터 프로세스 실행
30
        /// </summary>
31
        /// <param name="convertitem"></param>
32
        public bool ConvertProcessStart(ConvertDoc convertitem)
33
        {
34
            bool result = false;
35
            try
36
            {
37
           
38
                Process ConvertProcess = new Process();
39

    
40
                ProcessContext processSendData = new ProcessContext
41
                {
42
                    ConvertID = convertitem.ID,
43
                    ConnectionString = MarkusDBConnectionString,
44
                    ServiceStationUri = gServiceHostAddress.ToString(),
45
                    OriginFilePath = convertitem.DOCUMENT_URL,
46
                    SaveDirectory = convertitem.ConvertPath,
47
                    TempDirectory = DownloadTempFolder,
48
                    ReleaseWorkMemory = ReleaseWorkMemory,
49
                    MultiThreadMaxPages = MultiThreadMaxPages,
50
                    MinFontSize = MinFontSize,
51
                    SendStatusInterval = SaveStatusInterval,
52
                    UseResolution = UseResolution,
53
                    FontsFolder = FontsFolder
54
                };
55

    
56
                var sendData = ObjectToBytesStringConvert.ObjectToBytesString(processSendData);
57
                var convertPath = System.IO.Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Convert\\Markus.Service.ConvertProcess.exe");
58

    
59
                ProcessStartInfo startInfo = new ProcessStartInfo
60
                {
61
                    UseShellExecute = false,
62
                    FileName = convertPath,
63
                    WindowStyle = ProcessWindowStyle.Hidden,
64
                    CreateNoWindow = true,
65
                    ErrorDialog = false,
66
                    RedirectStandardError = false,
67
                    Arguments = $"{convertitem.ID.ToString()} {AESEncrypter.Encrypt(sendData)}"
68
                    //Arguments = $"{convertitem.ConvertID.ToString()} {convertitem.ProjectNumber} {AESEncrypter.Encrypt(MarkusDBConnectionString)} {gServiceHostAddress} {DownloadTempFolder} {MultiThreadMaxPages}"
69
                };
70

    
71
                ConvertProcess.StartInfo = startInfo;
72
                ConvertProcess.EnableRaisingEvents = true;
73
                
74
                System.Diagnostics.Debug.WriteLine("convert process run : " + startInfo.Arguments);
75

    
76
                logger.Info($"convert process run : ConvertDoc ID:{convertitem.ID}" + startInfo.Arguments);
77

    
78
                if (ConvertProcess.Start())
79
                {
80
                    try
81
                    {
82
                        var processAffinity = ProcessorAffinityList.Except(AliveConvertQueue.Select(f => (long)f.ProcessorAffinity));
83

    
84
                        long currentAffinity = 0;
85

    
86
                        if (processAffinity.Count() > 0)
87
                        {
88
                            currentAffinity = processAffinity.First();
89

    
90
                            //int bitMask = 1 << (convertitem.ProcessorAffinity - 1);
91
                            //bitMask |= 1 << (anotherUserSelection - 1); / //  프로세스 두개 이상 선택
92

    
93
                            ConvertProcess.ProcessorAffinity = new IntPtr(currentAffinity);
94
                            logger.Info($"convert process currentAffinity set {currentAffinity} : ConvertDoc ID:{convertitem.ID}");
95

    
96
                        }
97
                        else
98
                        {
99
                            // 모두 사용중일때 점유율이 작은 걸로 사용
100
                            var CurrentProcessAffinity = AliveConvertQueue.Where(x=>x.ProcessorAffinity > 0).Select(f => f.ProcessorAffinity).Distinct();
101

    
102
                            currentAffinity = CurrentProcessAffinity.Min();
103
                            ConvertProcess.ProcessorAffinity = new IntPtr(currentAffinity);
104

    
105
                            logger.Info($"convert process Affinity All use {currentAffinity} :  ConvertDoc ID:{convertitem.ID}");
106

    
107
                        }
108

    
109
                        var item = AliveConvertQueue.Find(x => x.Equals(convertitem));
110

    
111
                        if (item != null)
112
                        {
113
                            item.ProcessorAffinity = currentAffinity;
114
                        }
115
                    }
116
                    catch (Exception ex)
117
                    {
118
                        AliveConvertQueue.Remove(convertitem);
119
                        logger.Error("ConvertProcessStart error", ex);
120
                    }
121

    
122
                    logger.Info($"convert process run true ConvertDoc ID:{convertitem.ID}");
123
                    result = true;
124
                }
125
            }
126
            catch (Exception ex)
127
            {
128
                AliveConvertQueue.Remove(convertitem);
129
                throw new Exception("ConvertThread " + $" ConvertDoc ID:{convertitem.ID} {convertitem.PROJECT_NO} {AESEncrypter.Encrypt(MarkusDBConnectionString)} {gServiceHostAddress} {DownloadTempFolder} {MultiThreadMaxPages}", ex.InnerException);
130
            }
131
            finally
132
            {
133
                //GC.WaitForPendingFinalizers();
134
                //GC.Collect(2);
135
                //GC.Collect(2);
136
            }
137

    
138
            return result;
139
        }
140
    
141
        /// <summary>
142
        /// DB에 있는 대기중인 Item을 가져와서 프로세스 실행
143
        /// 
144
        /// </summary>
145
        public void setDataBaseWaitingList()
146
        {
147
            using (ConvertDocRepository database = new ConvertDocRepository(MarkusDBConnectionString))
148
            {
149
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
150

    
151
                var convertItems = database.GetWaitorErrorAsync(totalProcessCount).GetAwaiter().GetResult();
152

    
153
                foreach (var convert in convertItems)
154
                {
155
                    //ReflashSubService();
156

    
157
                    if (AliveConvertQueue.Count(x => x.ID == convert.ID 
158
                                              || x.DOCUMENT_ID == convert.DOCUMENT_ID  // 같은 경로로 다운로드 및 작업되어 추가
159
                                              || (x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL)) == 0)
160
                                                 //  같은 url을 다운로드시 서버의 퍼포먼스가 좋지 않으면 다운로드 오류 발생하여 추가
161
                    {
162
                        if (convert.STATUS > (int)StatusCodeType.None)
163
                        {
164
                            var result = database.SetCleanUpItemAsync(convert.ID, 1).GetAwaiter().GetResult();
165

    
166
                            if (result != 1)
167
                            {
168
                                throw new Exception($"SetCleanUpItem result :{result} {convert.ID}");
169
                            }
170
                        }
171

    
172
                        ConvertProcessAdd(convert.PROJECT_NO, convert.ID);
173
                        //PassConvertItem(convert.PROJECT_NO, convert.ID, convert.DOCUMENT_ID);
174

    
175
                        //System.Threading.Thread.Sleep(1000);
176
                    }
177
#if DEBUG
178
                    else
179
                    {
180
                        if (AliveConvertQueue.Where(x => x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL) is var items)
181
                        {
182
                            if (System.Environment.UserInteractive)
183
                            {
184
                                if (items.Count() > 0)
185
                                {
186
                                    Console.WriteLine($"Same DOCUMENT_URL : {((StatusCodeType)items.First().STATUS).ToString()} - {items.First().DOCUMENT_URL}");
187
                                }
188
                            }
189
                        }
190

    
191
                        if (AliveConvertQueue.Count(x => x.ID == convert.ID) > 0)
192
                        {
193
                            if (System.Environment.UserInteractive)
194
                            {
195
                                Console.WriteLine($"same convert.ID : {convert.ID}");
196
                            }
197
                        }
198

    
199
                        if (AliveConvertQueue.Count(x=> x.DOCUMENT_ID == convert.DOCUMENT_ID) > 0)
200
                        {
201
                            if (System.Environment.UserInteractive)
202
                            {
203
                                Console.WriteLine($"same convert.DOCUMENT_ID : {convert.DOCUMENT_ID}");
204
                            }
205
                        }
206
                    }
207
#endif
208
                    /// 2022.11.28 수정
209
                    if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
210
                    {
211
                        break;
212
                    }
213
                }
214
            }
215
        }
216

    
217
        /// <summary>
218
        /// DB에 있는 대기중인 Item을 가져온다.
219
        /// </summary>
220
        //public void setDataBaseWaitingLista()
221
        //{
222

    
223
        //    List<EntityModel.CONVERTER_DOC> convertItems = new List<EntityModel.CONVERTER_DOC>();
224

    
225
        //    using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
226
        //    {
227
        //        // 전체 서비스의 process count 만큼 waiting item을 가져온다.
228
        //        int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
229
        //        convertItems = database.GetWaitConvertItems(this.RunProjectList, totalProcessCount).ToList();
230
        //    }
231

    
232
        //    foreach (var convert in convertItems)
233
        //    {
234
        //        //ReflashSubService();
235

    
236
        //        if (AliveConvertQueue.Count(x => x.ConvertID == convert.ID) == 0)
237
        //        {
238
        //            if (convert.STATUS > (int)StatusCodeType.None)
239
        //            {
240
        //                using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
241
        //                {
242
        //                    database.SetCleanUpItem(convert.ID, 1);
243
        //                }
244
        //            }
245
        //            ConvertProcessAdd(convert.PROJECT_NO, convert.ID);
246
        //            //PassConvertItem(convert.PROJECT_NO, convert.ID, convert.DOCUMENT_ID);
247

    
248
        //            //System.Threading.Thread.Sleep(1000);
249
        //        }
250

    
251
        //        /// 2022.11.28 수정
252
        //        if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
253
        //        {
254
        //            break;
255
        //        }
256
        //    }
257

    
258
        //}
259

    
260
        public bool IsDataBaseWaitingList(int overListCount)
261
        {
262
            bool result = false;
263

    
264
            try
265
            {
266
                using (ConvertDocRepository convertDatabase = new ConvertDocRepository(MarkusDBConnectionString))
267
                {
268
                    var convertItems = convertDatabase.GetWaitorErrorAsync(overListCount).GetAwaiter().GetResult();
269

    
270
                    if (convertItems.Count() > 0)
271
                    {
272
                        result = true;
273
                    }
274
                }
275
            }
276
            catch (Exception ex)
277
            {
278
                logger.Error($"IsDataBaseWaitingList Error",ex);
279
            }
280

    
281
            return result;
282
        }
283

    
284
        private async Task<bool> ReflashSubServiceAsync()
285
        {
286
            bool result = false;
287

    
288
            try
289
            {
290
                foreach (var subservice in StationServiceList)
291
                {
292
                    try
293
                    {
294
                        subservice.IsOnline = await SytemNet.PingAsync(subservice.Properties.SERVICE_ADDRESS);
295

    
296
                        if (subservice.IsOnline)
297
                        {
298
                            var alivelist = await subservice.Service.AliveConvertListAsync();
299

    
300
                            subservice.ConvertItems = alivelist.Cast<ConvertDoc>().ToList();
301
                            subservice.AliveCount = alivelist.Count();
302
                        }
303
                        else
304
                        {
305
                            logger.Error($"Connection Error {subservice.Properties.SERVICE_ADDRESS}");
306
                            subservice.ConvertItems = new List<ConvertDoc>();
307
                            subservice.AliveCount = subservice.Properties.PROCESS_COUNT;
308
                        }
309

    
310
                        result = true;
311
                    }
312
                    catch (Exception ex)
313
                    {
314
                        logger.Error($"ReflashSubService error - Service ID : {subservice.Properties.ID} ", ex);
315
                    }
316
                }
317
            }
318
            catch (Exception ex)
319
            {
320
                logger.Error($"ReflashSubService error", ex);
321
            }
322

    
323
            return result;
324
        }
325

    
326

    
327
        /// <summary>
328
        /// 
329
        /// </summary>
330
        /// <param name="ProjectNo"></param>
331
        /// <param name="ConvertID"></param>
332
        /// <param name="UniqueKey">Document ID(문서의 유일키)</param>
333
        private async void PassConvertItem(string ProjectNo,string ConvertDocID,bool isSubStation = false)
334
        {
335
            try
336
            {
337
                IEnumerable<SubStationServiceItem> stationList = null;
338

    
339
                //if (!isSubStation)
340
                //{
341
                    stationList = StationServiceList.Where(x => x.IsOnline);
342
                //}
343
                //else
344
                //{
345
                //    stationList = StationServiceList.Where(x => x.Properties.ID != this.ServiceID && x.IsOnline);
346
                //}
347

    
348
                if (stationList.SelectMany(x => x.ConvertItems).Count(c => c.PROJECT_NO == ProjectNo && c.ID == ConvertDocID) == 0)
349
                {
350
                    var station = stationList.OrderByDescending(x => x.Properties.PROCESS_COUNT - x.AliveCount).FirstOrDefault();
351

    
352
                    if (station != null)
353
                    {
354
                        if (station.Properties.PROCESS_COUNT - station.AliveCount > 0)
355
                        {
356
                            System.Diagnostics.Debug.WriteLine($"{station.Properties.SERVICE_ADDRESS}  {station.Properties.PROCESS_COUNT}/{station.AliveCount}");
357
                            var result = await station.Service.PassConvertAsync(ProjectNo, ConvertDocID);
358

    
359
                            if (!result.IsNullOrEmpty())
360
                            {
361
                                if (result.ToLower() == true.ToString().ToLower())
362
                                {
363
                                    Console.WriteLine($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
364
                                    logger.Info($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
365

    
366
                                    station.AliveCount++;
367
                                }
368
                                else
369
                                {
370
                                        logger.Error($"PassConvertItem Error result : {result} - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
371
                                }
372
                            }
373
                            else
374
                            {
375
                                logger.Error($"PassConvertItem result: Nulll; - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
376
                                System.Diagnostics.Debug.WriteLine("result : Nulll;");
377
                            }
378
                        }
379
                    }
380
                }
381
            }
382
            catch (Exception ex)
383
            {
384
                logger.Error($"setDataBaseWaitingList", ex);
385
            }
386
        }
387

    
388
        /// <summary>
389
        /// 컨버터 프로세스와 AiliveItems을 비교하여 AliveItems에 없는 경우 AliveItems을 제거
390
        /// </summary>
391
        private void CleanUpAliveQueueItems()
392
        {
393
            if (AliveConvertQueue.Count() > 0)
394
            {
395
                var processList = Process.GetProcessesByName("Markus.Service.ConvertProcess");
396

    
397
                if (processList.Length == 0)
398
                {
399
                    AliveConvertQueue.Clear();
400
                    System.Diagnostics.Debug.WriteLine("AliveConvertQueue.Clear()");
401
                }
402
                else
403
                {
404
                    var argumentList = processList.Where(x=> !x.HasExited).Select(f => f.Arguments().CommandLine).SelectMany(f => f).ToList();
405

    
406
                    List<ConvertDoc> convertItems = AliveConvertQueue;
407

    
408
                    try
409
                    {
410
                        if (convertItems.Count() > 0 && argumentList.Count() > 0)
411
                        {
412
                            for (int i = convertItems.Count - 1; i >= 0; --i)
413
                            {
414
                                if (argumentList.Count(x => x == convertItems[i].ID) == 0)
415
                                {
416
                                    System.Diagnostics.Debug.WriteLine($"AliveConvertQueue remove {convertItems[i].ID}");
417
                                    logger.Warn($"AliveConvertQueue remove {convertItems[i].ID}");
418
                                    AliveConvertQueue.Remove(convertItems[i]);
419

    
420
                                }
421
                            }
422
                        }
423
                    }
424
                    catch (Exception ex)
425
                    {
426
                        logger.Error("CleanUpAliveQueueItems error",ex);
427
                    }
428
                }
429
            }
430
        }
431

    
432
        /// <summary>
433
        /// AliveConvertQueue와 db를 비교하여 AliveConvertQueue에 없는 데이터를 초기화 하여 다시 컨버팅
434
        /// </summary>
435
        private async void CleanUpDataBaseItems()
436
        {
437
            try
438
            {
439
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
440

    
441
                using (DataBase.Repositories.ConvertDocRepository repository = new DataBase.Repositories.ConvertDocRepository(MarkusDBConnectionString))
442
                {
443
                    var items = repository.GetConvertingItemAsync(totalProcessCount).GetAwaiter().GetResult();
444

    
445
                    List<ConvertDoc> aliveItems = new List<ConvertDoc>();
446

    
447
                    aliveItems.AddRange(this.AliveConvertList());
448

    
449
                    foreach (var item in StationServiceList.Where(x => x.IsOnline))
450
                    {
451
                        var serviceItems = await item.Service.AliveConvertListAsync();
452
                        aliveItems.AddRange(serviceItems.Cast<ConvertDoc>());
453
                    }
454

    
455
                    if (aliveItems.Count() > 0)
456
                    {
457
                        logger.Warn($"aliveItems  : {string.Join(",",aliveItems.Select(x=>x.ID))}");
458

    
459
                        foreach (var item in items)
460
                        {
461
                            if (aliveItems.Count(x => x.ID == item.ID) == 0)
462
                            {
463
                                Console.WriteLine($"SetCleanUpItem  : {item.ID}");
464
                                logger.Warn($"SetCleanUpItem  : {item.ID}");
465
                                repository.SetCleanUpItemAsync(item.ID, 0).GetAwaiter().GetResult();
466
                            }
467
                        }
468
                    }
469
             
470
                }
471
            }
472
            catch (Exception ex)
473
            {
474
                throw new Exception("CleanUpDataBaseItems Error ", ex);
475
            }
476
        }
477

    
478
        public void Stopprocess()
479
        {
480
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
481

    
482
            for (int i = process.Count() - 1; i >= 0 ; i--)
483
            {
484
                try
485
                {
486
                    Console.WriteLine($"{i} Process Kill");
487
                    process[i].Kill();
488
                }
489
                catch (Exception ex)
490
                {
491
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
492
                }
493
            }
494
        }
495

    
496
        /// <summary>
497
        /// finish가 호출되고 살아있는 프로세스라고 추정됨
498
        /// </summary>
499
        public void DeadLockProcessKill()
500
        {
501
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
502

    
503
            for (int i = process.Count() - 1; i >= 0; i--)
504
            {
505
                try
506
                {
507
                    var commandLines = process[i].Arguments().CommandLine;
508

    
509
                    if (commandLines.Count() > 0)
510
                    {
511
                        if (ServiceStation.AliveConvertQueue.Count(f => f.ID == commandLines[0]) == 0)
512
                        {
513
                            process[i].Kill();
514
                        }
515
                    }
516
                }
517
                catch (Exception ex)
518
                {
519
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
520
                }
521
            }
522
        }
523

    
524
        private async void ConvertFinish(ConvertDoc convertitem)
525
        {
526
            try
527
            {
528
                System.Diagnostics.Debug.WriteLine("Convert Finish : " + convertitem.ID);
529

    
530
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
531

    
532
                List<string> deleteItems = new List<string> { convertitem.ID };
533

    
534

    
535
                ServiceStation.AliveConvertQueue.RemoveAll(x=>deleteItems.Any(y=>y == x.ID));
536

    
537
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
538

    
539
                if (IsStation)
540
                {
541
                    if (!IsReleaseItems)
542
                    {
543
                        System.Diagnostics.Debug.WriteLine("ConvertFinish ReleaseItems call");
544
                        ReleaseItems();
545
                    }
546
                }
547
                else
548
                {
549
                    if (StationClient != null)
550
                    {
551
                       await  StationClient.ReleaseConvertItemsAsync();
552
                    }
553
                }
554
                //if (ServiceStation.AliveConvertQueue.Count() < MultiProcessCount)
555
                //{
556
                //    setDataBaseWaitingList();
557
                //}
558
            }
559
            catch (Exception ex)
560
            {
561
                logger.Error("ConvertFinish Error",ex);
562
            }
563
        }
564
    }
565
}
클립보드 이미지 추가 (최대 크기: 500 MB)