V # da bir funktsiyani takrorlamasdan, bu endi istisno qilmaydi

SOAP interfeysini chaqiradigan bir sinf bor va ma'lumotlarning bir qatorini oladi. Biroq, agar bu so'rov tugashi bilan istisno qilsa. Bu yaxshi. Biroq, mening dasturim bu chaqiruvni qayta ishlashga urinishni xohlayman. Vaqt o'tishi bilan men bu chaqiruvni muvaffaqiyatli bajarguncha davom ettirmoqchiman. Buni qanday amalga oshirishim mumkin?

Misol uchun:

try
{
   salesOrdersArray = MagServ.salesOrderList(sessID, filter);
}
catch
{
   ?? What Goes Here to FORCE the above line of code to rerun until it succeeds.
}
7
Istisno qilmaslik uchun vaqt tugashini oshiringmi?
qo'shib qo'ydi muallif ChaosPandion, manba
Bu javoblarning barchasidan birontasi sizdan ma'lum bir istisno tutishni aytmaydi. Sinov blokingizda salesOrderList ni olish uchun yaroqsiz holatda narsalar mavjud bo'lsa nima bo'ladi? Qayta urinish hech qachon muvaffaqiyatli bo'lmaydi.
qo'shib qo'ydi muallif Marc, manba
Siz faqat usulni chaqiruvchi blokdan yana chaqira olasiz: BUT - agar xizmat uzoq vaqt davomida o'chib ketgan bo'lsa nima bo'ladi? Usul 24 soat davomida o'z-o'zidan ishga tushirilishini xohlaysizmi? Uni ko'p sonli sinovlarga cheklashni tavsiya qilaman.
qo'shib qo'ydi muallif Tim, manba

11 javoblar

Siz faqat abadiy ko'chaga kirishingiz kerak:

while (true)
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
        break;//Exit the loop. Could return from the method, depending
              //on what it does...
    }
    catch
    {
       //Log, I suspect...
    }
}

Esingizda bo'lsa, deyarli albatta emas, balki , albatta, abadiy pastadir. Siz, ehtimol, maksimal miqdorda urinishlaringiz bo'lishi kerak va ehtimol maxsus maxsus ni qo'lga olishingiz kerak. salesOrderList (noan'anaviy usul nomi, btw) ArgumentNullException yoki all chunki siz xatolik yuz berdingiz va filter null ... siz haqiqatdan ham CPU'nizning 100 foizini birlashmoqchimisiz?

16
qo'shib qo'ydi
@Ta': Quyidagi xatboshini qo'shib qo'ydim - asosan kod savolga bevosita javob beradi, lekin xat bu yaxshi fikr emasligini tushuntiradi :)
qo'shib qo'ydi muallif Jon Skeet, manba
@psyklopz: Siz catch blokidagi istisno turini belgilaysiz: catch (SoapException) va hokazo. Siz bir nechta catch bloklarida bir nechta alohida istisno turlarini tanlashingiz mumkin.
qo'shib qo'ydi muallif Jon Skeet, manba
Men shunga o'xshash narsani amalga oshirganimda, ba'zi bir xizmatni onlayn rejimda kutayotgan CPU% 100 foizini ishlatmaslik uchun tegishli vaqtni Sleep ga qo'ydim. Hatto cheklangan eksponensial backoff (masalan, TCP kabi) kichik tarmoqli shovqinlardan tezda tiklanadi, lekin xizmat uzoq vaqt davomida o'chirilgan bo'lsa, bir necha daqiqada bir marta ishlaydi.
qo'shib qo'ydi muallif Gabe, manba
Maxsus istisnolar uchun +1, tahriringizda sizning sharhlarimni yozyapman.
qo'shib qo'ydi muallif Marc, manba
Bu (potensial) tizim resurslarini bog'lash va/yoki qo'ng'iroq qilish ilovasini javob bermayaptimi? Men uchun eng yaxshi echimga o'xshamaydi ...
qo'shib qo'ydi muallif Tim, manba
Bundan tashqari, avvalgi vaqtni olishingiz va keyin diff b/w ga qadar kutishingiz mumkin, endi esa> 5 soniyadan keyin chiqib ketishingiz mumkin (yoki xohlagancha uzoq)
qo'shib qo'ydi muallif Mr Universe, manba
Bilaman, muayyan istisnolardan, SOAP xatolaridan va boshqalarni olaman.
qo'shib qo'ydi muallif psyklopz, manba

Agar siz takrorlashni o'zgartira olmasangiz, unda quyida ishlashingiz kerak. salesOrdersArray null ga sozlangan bo'lishi kerak.

while(salesOrdersArray == null)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
      //Log failure
    }
}
4
qo'shib qo'ydi
+1: Men buni Jonning javobidan yaxshiroq yaxshi ko'raman. O'ylaymanki, bu halqaning so'nggi holatini yanada aniqroq qiladi.
qo'shib qo'ydi muallif Brian, manba

Bu istisnolardan boshqarish oqimi sifatida foydalanish uchun umuman yaxshi fikr emas, lekin bu siz talab qilgan narsani amalga oshiradi.

bool Caught = true;
while (Caught)
try
{
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    Caught = false;
}
catch
{
    Caught = true;
}
1
qo'shib qo'ydi

Xizmat qo'ng'iroqlarini saqlash uchun tranzaksiya quyruq (MSMQ) dan foydalanaman. Agar loop, xabarlarni dequeue bo'ladi va agar chaqiruv xatlar hali ham navbatda ko'rinmasa TransactionScope-da xizmatni chaqiradi. Xabarni tugatish uchun vaqtni qo'shib, o'chirish vaqti tugashi mumkin. Bu echim, albatta, ishonchli echimni istasangiz yaxshi bo'ladi, chunki bu operatsiyani bajarish juda muhimdir.

1
qo'shib qo'ydi

Siz loop tuzilishi ichida sinash/tutish blokini joylashtirishingiz kerak. Protsessoringizning 100% iste'mol qilmaslik uchun catch blokida Thread.Sleep joylashtirilsin, shuning uchun istisno har doim sodir bo'lganda, protsessorni boshqa narsalarni bajarish uchun bo'sh qoldiring.

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch {
        Thread.Sleep(1000);
    }
}

Bundan tashqari, faqat takrorlash istisnosiz va boshqa istisnolardan o'tish uchun maxsus holatni ham belgilashingiz mumkin.

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch (TimeOutException) {
        Thread.Sleep(1000);
    }
}

Shuni unutmangki, TimeOutException maxsus vaziyatning haqiqiy nomi bilan almashtirilishi kerak ... Bu haqiqiy ism yoki noma'lumligini bilmayman.

Bundan tashqari, millisektsiyada berilgan va takroriy miqdordagi uyqu vaqtini moslashtira oladigan bo'lsak, 1000 me'yorni 100 marta takrorlash 1 minut va 40 sekundni maksimal kutish imkonini beradi, shuningdek, operatsiya vaqtining o'zi.

1
qo'shib qo'ydi

Ushlab ko'ring

bool failed = false;
do {
 Ushlab ko'ring
 {
  salesOrdersArray = MagServ.salesOrderList(sessID, filter);
 }
 catch
 {
  failed = true;
 }
} while(failed);

Agar siz bu harakatlaringiz hech qachon muvaffaqiyatli bo'lmasa, keyingi harakatlaringiz abadiy pastga sabab bo'lishi mumkin ...

0
qo'shib qo'ydi

Men buni cheksiz ko'p marta qilishingizni tavsiya etmasam ham, bitta gapdan alohida vazifani bajarishingiz mumkin:

void GoConnect()
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
        GoConnect();
    }
}
0
qo'shib qo'ydi
bool repeat = true;
while (repeat)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
       repeat = false;
    }
    catch
    {
    }
}
0
qo'shib qo'ydi

Ushbu muammoni hal qilish uchun men ushbu namunaga amal qilaman:

    public void Send(String data, Int32 attemptNumber)
    {
        try
        {
            yourCodeHere(data);
        }
        catch (WebException ex)
        {
            if (attemptNumber > 0)
                Send(data, --attemptNumber);
            else
                throw new AttemptNumberExceededException("Attempt number exceeded!", ex);
        }
        catch (Exception ex)
        {
            //Log pourpose code goes here!
            throw;
        }
    }

Uzluksiz harakat qilish siz uchun yaxshi fikr emas, chunki siz abadiy jarayonga ega bo'lishingiz mumkin. Agar maqsadga erishish uchun ko'plab tashabbuslar kerak bo'lsa, bu erda juda ko'p raqamni belgilang.

Shaxsan men o'zimning donishmandni bir necha millisekundlarni kutmoqchi deb hisoblayman, yoki Thread.Sleep (1000) ni ishga tushirgandan keyin bir necha soniyalar o'tgach, yuborish (ma'lumotlar); --- masalan, stsenariy uchun dono deb hisoblasangiz, kutish vaqtini kamaytirish yoki kamaytirish uchun attempNumber o'zgaruvchisini ishlating.

0
qo'shib qo'ydi
Nima uchun men emas? Mening fikrim Jon Skeet bilan bir xil, u yozgan kod ostida
qo'shib qo'ydi muallif Renato Gama, manba
Rahmat @asawyer bu haqida bilmas edi, shuning uchun javobimni tahrir qildim! bu hozir o'qmi?
qo'shib qo'ydi muallif Renato Gama, manba
bu haqiqiy ma'noga ega ...! hech qachon bu haqda o'ylamagan edim ... seni zerikish uchun afsuslanyapsizmi, hozir nima haqida?
qo'shib qo'ydi muallif Renato Gama, manba
chiqish ex. Buni qilmang!
qo'shib qo'ydi muallif asawyer, manba
qo'shib qo'ydi muallif asawyer, manba
Ikkita narsalar: 1- Siz asosiy istisnosizni sinab ko'rishni xohlamaysiz va agar qilsangiz, bu faqatgina jurnalga yozilish uchun va faqat throw again. 2 - Hech qachon bazani Exception sinfiga tashlamang. Istagan kodni Exception -ni tutishning yomon dasturiga majbur qilasiz. Yana mos keladigan pastki sinfdan foydalaning yoki o'zingizni yaratgin.
qo'shib qo'ydi muallif asawyer, manba
Eng yaxshi amaliyotlarni o'qib chiqishga ozgina vaqt sarflang va siz hech qachon biznesda qatnashasiz. Bir-ikkita yaxshi havolalar: blogs.msdn. MAQOMOTI/b/ericlippert/archive/2008/09/10/and hellip; codeproject.com/KB/architecture/exceptionbestpractices.aspx
qo'shib qo'ydi muallif asawyer, manba
Oh tahrir qilishni nazarda tutasiz. Yaxshi ko'rinadi! :)
qo'shib qo'ydi muallif asawyer, manba

Quyidagilarni sinab ko'ring:

var failed = true;
while (failed)
{
  try 
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    failed = false;
  }
  catch
  {
  }
}

Tartibga solish: Vau! Katta aqllar ham xuddi shunday deb o'ylaydi! :)

0
qo'shib qo'ydi
while(salesOrdersArray == null){

  try
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
  }
  catch(salesOrderException e)
  {
     log(e.message);
  }
}

Bu abadiy ishlaydi va istisnolardan asta-sekinlik bilan ishlatiladi. Funktsiyani istisno qilish o'rniga null qaytaradigan tarzda o'zgartirishingiz mumkinmi? Agar siz ushbu qo'ng'iroq muntazam ravishda bajarilmasligini kutmoqchi bo'lsangiz, sinash/ta'qib qilish blokidan foydalanmang.

0
qo'shib qo'ydi