İşlenmeyen istisnalar nasıl tedavi edilir? (Uygulamayı sonlandırın, canlı tutun)


30

Bir masaüstü uygulamasında işlenmeyen bir istisna olduğunda, en iyi uygulama nedir?

Kullanıcıya bir mesaj göstermeyi düşünüyordum, böylece desteğe başvurabilecekti. Uygulamayı yeniden başlatması için kullanıcıya öneririm, ancak zorlamak değil. Burada tartışılana benzer: ux.stackexchange.com - Beklenmeyen uygulama hatalarını ele almanın en iyi yolu nedir?

Proje bir .NET WPF uygulamasıdır, bu nedenle tarif edilen teklif şöyle görünebilir (Bu basitleştirilmiş bir örnek olduğuna dikkat edin. Muhtemelen kullanıcı "Ayrıntıları Göster" e tıklayıncaya ve bazı işlevsellikler sağlayıncaya kadar istisna ayrıntılarını gizlemek mantıklı olacaktır. hatayı kolayca bildir):

public partial class App : Application
{
    public App()
    {
        DispatcherUnhandledException += OnDispatcherUnhandledException;
    }

    private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        LogError(e.Exception);
        MessageBoxResult result = MessageBox.Show(
             $"Please help us fix it and contact support@example.com. Exception details: {e.Exception}" +
                        "We recommend to restart the application. " +
                        "Do you want to stop the application now? (Warning: Unsaved data gets lost).", 
            "Unexpected error occured.", MessageBoxButton.YesNo);

        // Setting 'Handled' to 'true' will prevent the application from terminating.
        e.Handled = result == MessageBoxResult.No;
    }

    private void LogError(Exception ex)
    {
        // Log to a log file...
    }
}

Uygulamada (ViewModels Komutları veya harici olayların olay işleyicisi) o zaman sadece belirli dışsal istisnayı yakalarım ve diğer tüm istisnaların (boneheaded ve bilinmeyen istisnalar) yukarıda açıklanan "Son başvuru işleyicisi" ne yapmasına izin verirdim. Kemik kafalı ve dışsal istisnalar tanımına bir göz atın: Eric Lippert - Vexing istisnaları

Kullanıcının, uygulamanın sonlandırılıp sonlandırılmayacağına karar vermesine izin vermek mantıklı mı? Uygulama sonlandırıldığında, o zaman kesinlikle tutarsız bir durumunuz olmaz ... Öte yandan, kullanıcı kaydedilmemiş verileri kaybedebilir veya uygulama yeniden başlatılıncaya kadar başlatılan herhangi bir harici işlemi durduramaz.

Yoksa, yazdığınız uygulamanın türüne bağlı olarak, işlenmeyen istisnalar halinde başvuruyu sonlandırmanız gerekip gerekmediği kararı mı? Code Complete, Second Edition'da açıklandığı gibi sadece "sağlamlık" ile "doğruluk" arasında bir takas mı var?

Ne tür bir uygulamadan bahsettiğimize sizlere bir bağlam vermek için: Uygulama, kimyasal laboratuar cihazlarını kontrol etmek ve ölçülen sonuçları kullanıcıya göstermek için kullanılır. Bunu yapmak için WPF uygulamaları bazı servislerle iletişim kurar (yerel ve uzak servisler). WPF uygulaması doğrudan enstrümanlarla iletişim kurmaz.


27
Bir istisna beklemiyorsanız, uygulamanın güvenle devam edebileceğinden nasıl emin olabilirsiniz?
Deduplicator

2
@Deduplicator: Elbette, emin olamazsınız. Daha önce Matthew’ün cevabına yorum yazdığı gibi : "Evet, uygulama geçersiz durumda olabilir. Belki bazı ViewModel’ler yalnızca kısmen güncellenmiştir. Ancak bu herhangi bir zarar verebilir mi? Kullanıcı verileri yeniden yükleyebilir ve geçersiz bir şey olursa servise gönderin, servis yine de kabul etmeyecektir. Uygulamayı yeniden başlatmadan önce kaydedebilmesi kullanıcı için daha iyi olmaz mı? "
Jonas Benz

2
@Voo Yani, uygulamanın her zaman bir istisna bekleyerek güvenle devam edebileceğinden emin misin? Beklenmedik bir istisna alma önceliğini reddediyor gibisiniz.
Deduplicator

2
Her durumda, lütfen hata mesajını kopyalanabilir duruma getirin. Alternatif olarak, hangi günlük dosyasına yazıldığını söyleyin.
ComFreek

2
Taşıma, kesin bir işlem olduğu anlamına gelmez. Uygulamanın güvenle devam edebileceğinden eminseniz, istisnayı ele aldınız.
chepner

Yanıtlar:


47

Elektrik kesintisi veya tüm sistemi çökerten farklı bir arkaplan işlemi gibi, programınızın işlenmemiş bir istisnadan daha fazla nedenlerle sona ermesini beklemeniz gerekir. Bu nedenle feshedebilir ve uygulamayı yeniden başlatmak için öneriyoruz, ancak bazı önlemlerle için böyle bir yeniden başlatma sonuçlarını hafifletmek ve olası veri kaybını en aza indirmek .

Aşağıdaki noktaları analiz etmeye başlayın:

  • Bir program sonlandırılması durumunda gerçekte ne kadar veri kaybolabilir?

  • Bu tür bir kayıp gerçekten kullanıcı için ne kadar ciddi? Kayıp veriler 5 dakikadan daha kısa sürede yeniden yapılandırılabilir mi, yoksa bir günlük çalışmayı kaybetmekten mi bahsediyoruz?

  • Bazı "ara yedekleme" stratejisini uygulamak ne kadar çaba harcar? Bunu yazmayınız, çünkü bir yorumda yazdığınız gibi, "kullanıcının bir değişiklik sebebi girmek zorunda kalacağı" gibi düzenli bir kaydetme işleminde. Bir programın otomatik olarak çökmesinden sonra yeniden yüklenebilecek geçici bir dosya veya durum gibi bir şey düşünün. Birçok üretkenlik yazılımı türü bunu yapar (örneğin, MS Office ve LibreOffice, "otomatik kaydetme" özelliğine ve çökme kurtarma özelliğine sahiptir).

  • Verilerin yanlış veya bozuk olması durumunda, kullanıcı bunu kolayca görebilir (belki programı yeniden başlattıktan sonra)? Evetse, kullanıcının verileri kaydetmesine izin verme seçeneği sunabilirsiniz (küçük bir olasılıkla bozuk olabilir), ardından yeniden başlatmayı zorlayın, yeniden yükleyin ve kullanıcının verilerin iyi görünüp görünmediğini kontrol etmesine izin verin. Eski sürümün bozulmasını önlemek için düzenli olarak kaydedilen son sürümün üzerine yazmadığınızdan emin olun (bunun yerine geçici bir yere / dosyaya yazın).

Eğer böyle bir "ara yedekleme" stratejisi mantıklı bir seçenek ise, sonuçta uygulamaya ve mimarisine ve ilgili verinin doğasına ve yapısına bağlıdır. Ancak, kullanıcı 10 dakikadan daha az bir süre çalışmayı kaybederse ve böyle bir çökme haftada bir veya daha nadiren meydana gelirse, muhtemelen buna çok fazla yatırım yapmazdım.


10
en.wikipedia.org/wiki/Crash-only_software , ve Android uygulamalarının zorunluluklara göre çalışması.
Mooing Duck

3
Mükemmel cevap - ve olayları daha geniş bir bağlamda ele almanın güzel bir örneği (bu durumda “herhangi bir çökme durumunda veri kaybını nasıl önleyebiliriz?”) Daha iyi bir çözüme yol açar.
sleske

1
Eski verilerin üzerine yazmamanız gerektiğine dikkat etmek için küçük bir düzenleme yaptım - umarım sakıncası yoktur.
sleske

1
@MooingDuck Çok sayıda Android uygulaması (oyunlar gibi) kaza durumunda durumlarını kaybediyor.
user253751

1
@ immibis: Evet, Android gerçekten de çok düşük kalitede uygulamalara sahip.
Mooing Duck

30

Geliştirdiğiniz uygulamaya bir ölçüde bağlıdır ancak genel olarak başvurunuz işlenmeyen bir istisna ile karşılaşırsa uygulamayı sonlandırmanız gerektiğini söyleyebilirim.

Niye ya?

Çünkü artık uygulama durumunda herhangi bir güveniniz olamaz.

Kesinlikle, kullanıcıya yararlı bir mesaj verin, ancak uygulamayı sonlandırmanız gerekir.

Bağlamınız göz önüne alındığında, kesinlikle uygulamanın sonlandırılmasını istiyorum. Laboratuarda çalışan yazılımların bozuk çıktılar üretmesini istemiyorsunuz ve bu istisnayı ele almayı düşünmediğinizden, bunun neden atıldığı ve ne olduğu hakkında hiçbir fikriniz yok.


Son kısımda uygulama hakkında içerik bilgisi eklemeye çalıştım.
Jonas Benz

10
@JonasBenz Uygulamayı yeniden başlatmadan önce tasarruf ederse kullanıcı için daha iyi olmaz mı? Evet, fakat kullanıcının kaydedeceği verilerin geçerli ve bozuk olmadığını nasıl anlarsınız? Bu noktada, beklenmeyen bir istisna var ve nedenini gerçekten bilmiyorsun. En rahatsız edici yol, kullanıcıya rahatsız edici de olsa, uygulamayı sonlandırmaktır. Kullanıcı kaydetme işi ile ilgileniyorsanız, sürekli tasarruf stratejisi kullanırsınız. Yine, hepsi yazdığınız uygulamaya bağlıdır.
Matthew,

4
Evet, aynı şekilde tartışabilirim: Devam düğmesinin varlığına katılmıyorum. Sorun şu ki, eğer uygulama geliştiricisi güvenli bir şekilde devam edip edemeyeceğinizi bilmiyorsa, kullanıcı nasıl bilebilir? İşlenmeyen bir istisna alırsanız, bu beklemeyeceğiniz bir hatanız olduğu ve bu noktada ne olduğunu kesin olarak söyleyemeyeceğiniz anlamına gelir. Kullanıcı çalışmalarını kaybetmek istemeyeceği için devam etmek isteyecek, bunu anlıyorum, ancak uygulamanız bu hata nedeniyle hatalı sonuçlar üretse bile devam etmelerine izin vermek istiyor musunuz?
Matthew

3
@Matthew "eğer siz uygulama geliştirici güvenli bir şekilde devam edip edemeyeceğinizi bilmiyorsanız, kullanıcı nasıl bilebilir" , geliştirici kodu ne zaman yazdığını bilmiyordu. Kullanıcı böyle bir hatayla karşılaştığında, bilinen olabilir. Kullanıcı hangi kullanıcı forumlarından, destek kanallarından ve neyden geldiğini öğrenebilir ya da sadece verilerinin başına ne geldiğini test ederek ve görünce ... Anladığım kadarıyla, kullanıcı özelliği olarak biraz belirsiz ve tehlikeli, sadece zamanın geldiğine dikkat çekiyor. Kullanıcının gerçekten "devam etmenin" mantıklı olup olmadığını bilmesi mümkün.
Hyde

1
@JonasBenz, Windows 3.1 altında, bir program yasadışı bir bellek erişimi gerçekleştirdiğinde ortaya çıkan iletişim kutusunda, programın çalışmaya devam etmesine izin veren bir "yoksay" düğmesine sahipti. Bundan sonraki her Windows sürümünde bu düğmenin bulunmadığını not edersiniz.
Mark

12

Bunun kimyasal bir laboratuvar için yapıldığını ve uygulamanızın aletleri doğrudan kontrol etmediğini, bunun yerine diğer servislerden kontrol ettiğini düşünün:

Mesajı gösterdikten sonra sonlandırmayı zorla. İşlenmeyen bir istisnadan sonra başvurunuz bilinmeyen bir durumda. Hatalı komutlar yollayabilir. Nazal iblisleri bile çağrıştırabilir . Bir hatalı komut potansiyel pahalı reaktifler veya ekipman veya kişilere getirmek tehlike atık olabilir .

Ama başka bir şey yapabilirsin: yeniden başlattıktan sonra zarafetle iyileş . Uygulamanızın, çöktüğünde arka plan hizmetlerini kendisiyle azaltmadığını farz ediyorum. Bu durumda devleti onlardan kolayca kurtarabilirsin. Veya daha fazla devletiniz varsa, kaydetmeyi düşünün. Veri atomitesi ve bütünlüğü için hükümleri olan bir depoda (SQLite belki?)

Düzenle:

Yorumlarda belirtildiği gibi, kontrol ettiğiniz işlem, kullanıcının tepki vermek için vakti olmayacak kadar hızlı değişiklikler gerektirebilir. Bu durumda, zarif durum kurtarma işlemine ek olarak uygulamayı sessizce yeniden başlatmayı düşünmelisiniz.


Takip komutları gerektiren bir durumda sonlandırma RIGHT NOW, kimya laboratuarında aynı derecede tehlikeli olabilir.
Oleg V. Volkov

@ OlegV.Volkov yani fesih üzerine kendinizi yeniden başlatmak olabilir? Bir GUI'yi başlatan iyi bir bilgisayarda yüzlerce milisaniye üst sırada olmanız gerekir. İşlem daha zor zamanlamaları gerektiriyorsa, gerçek zamanlı olmayan bir işletim sisteminde kontrol uygulanmayacaktır. OP olmasına rağmen son risk değerlendirmesini kim yapmalı?
Jan Dorniak

@ OlegV.Volkov olsa iyi bir nokta, bu yüzden cevabı üzerine fikrimi ekledi.
Jan Dorniak

8

Bu soruyu genellikle programın en üst düzeyinde yanıtlamaya çalışmak akıllıca bir oyun değildir.

Eğer bir şey tamamen yoluna girmişse ve uygulamanın mimarisinin hiçbir noktasında kimse bu davayı göz önüne almadıysa, hangi eylemlerin güvenli olduğu ya da güvenli olmadığı konusunda yapabileceğiniz hiçbir genellemeniz yoktur.

Bu nedenle, hayır, kullanıcının uygulamanın kurtarmaya çalışıp çalışmayacağını seçmesine izin vermek kesinlikle kabul edilebilir bir tasarım değildir, çünkü uygulama ve geliştiriciler, bunun mümkün olup olmadığını ya da akıllıca olup olmadığını anlamak için gerekli olan özeni göstermediğini açıkça göstermiştir. .

Bununla birlikte, uygulama mantık veya davranışının bu tür bir başarısızlık kurtarması ile tasarlanan yüksek değerli bölümleri varsa ve bu durumda onları kaldırarak kullanmak mümkündür, o zaman elbette, bunu yapın - Bu durumda , kullanıcıdan kurtarmayı denemek isteyip istemediğini veya yalnızca onu aramak isteyip istemediklerini sorup bırakıp yeniden başlamak isteyip istemediğini sorması kabul edilebilir.

Bu tür bir kurtarma, tüm (veya hatta çoğu) programlar için genel olarak gerekli değildir veya tavsiye edilmez, ancak bu derece operasyonel bütünlüğün gerekli olduğu bir program üzerinde çalışıyorsanız, bu tür bir sunumun yapılması şart olabilir. Bir kullanıcıya istemi yapmak aklı başında bir şey olurdu.

Herhangi bir özel başarısızlık kurtarma mantığı leiu olarak - Hayır, bunu yapma. Kelimenin tam anlamıyla ne olacağı hakkında hiçbir fikrin yok, eğer yapsaydın, istisnayı daha da yakalar ve ele alırdın.


Ne yazık ki, "Bazı konumlardan alınan verilere sahip bir nesne oluşturma" gibi birçok işlem için, işlemin tamamlanamadığını belirten istisnalar arasında bir ayrım yoktur, ancak bu girişimin daha ciddi bir şey olduğunu belirtenlerin yan etkileri yoktur. yanlış gitti. Bir kaynağı yükleme girişiminin bir nedenden beklenmeyen bir sebepten ötürü başarısız olması, eğer genellikle nesneyi inşa edememe konusunda hazırlıklıysa ölümcül bir hatayı zorlamamalıdır. Önemli olan yan etkiler, ki ne yazık ki istisna çerçevelerin göz ardı ettiği bir şey.
supercat

@supercat - Bir hatayı tanımlayabilirseniz, onu kaldırabilirsiniz. Eğer tespit edemezseniz, neyin yanlış gittiğini ortaya çıkarmak için uygulamanın durumunu kontrol etmek için bir rutin yazmadığınız sürece uygulamanın üstesinden gelemezsiniz. Hatanın ne olabileceği önemli değil, açıkça tespit ettiğimizi, genellikle yakalanmamış istisnaları ele almaya çalıştığımızı bilmediğimizi açıkça belirledik.
Demir Gremlin

3

"İstisna istisnalar", yani öngörmediğiniz istisnalar ile ilgili sorun, programın hangi durumda olduğunu bilmemenizdir. Örneğin, kullanıcının verilerini kaydetmeye çalışmak aslında daha fazla veriyi tahrip edebilir .

Bu nedenle başvuruyu sonlandırmalısınız.

George Candea ve Armando Fox'un Crash- Only Yazılımı adında çok ilginç bir fikir var . Buradaki fikir, yazılımınızı kapatmanın tek yolu çökmesine neden olacak şekilde tasarlarsanız ve onu başlatmanın tek yolu bir çökmeden kurtulmak olacaksa, o zaman yazılımınız daha esnek olur ve hata kurtarma olur. kod yolları çok daha ayrıntılı olarak test edilecek ve uygulanacaktır.

Kazadan sonra bazı sistemlerin düzenli bir kapanmadan daha hızlı başladığını fark ettikten sonra bu fikri ortaya çıkardılar .

İyi, artık ilgili bir örnek olmamakla birlikte, Firefox'un yalnızca bir çökmeden kurtarıldığında daha hızlı başlayan değil aynı zamanda daha iyi bir başlangıç ​​deneyimine sahip olan eski sürümleri de var ! Bu sürümlerde, Firefox'u normal olarak kapatırsanız, tüm açık sekmeleri kapatır ve tek bir boş sekme ile başlar. Oysa bir kazadan kurtarırken, çarpışma anında açık sekmeleri geri yükleyecektir. (Bu, geçerli tarama içeriğinizi kaybetmeden Firefox'u kapatmanın tek yoluydu.) Peki, insanlar ne yaptı? Sadece Firefox'u hiç kapatmamışlar ve bunun yerine her zaman pkill -KILL firefoxeddiler.

Orada Linux Haftalık News Valerie Aurora tarafından çarpışma sadece yazılım hakkında güzel bir writeup . Yorumlar da okunmaya değer. Örneğin, yorumlardaki bir kişi haklı olarak bu fikirlerin yeni olmadığını ve aslında Erlang / OTP tabanlı uygulamaların tasarım ilkelerine eşit ya da daha az eşdeğer olduğunu belirtiyor. Ve elbette, bugün, Valerie’den 10 yıl sonra ve orijinal makaleden 15 yıl sonra buna bakıldığında, mevcut mikro hizmet yutturucusunun yine aynı fikirleri yeniden icat ettiğini fark edebiliriz. Modern Bulut ölçeğinde veri merkezi tasarımı aynı zamanda daha büyük bir ayrıntı düzeyi örneğidir. (Herhangi bir bilgisayar, sistemi etkilemeden herhangi bir zamanda çökebilir.)

Ancak, yalnızca yazılımınızın çökmesine izin vermek yeterli değildir. Bunun için tasarlanması gerekiyor. İdeal olarak, yazılımınız her birinin bağımsız olarak çökmesine neden olabilecek küçük, bağımsız bileşenlere ayrılır. Ayrıca, "çarpma mekanizması" kilitlenen bileşenin dışında olmalıdır.


1

İstisnaların çoğunun üstesinden gelmenin doğru yolu, bunun sonucunda bozuk bir durumda olabilecek herhangi bir nesneyi geçersiz kılmak ve geçersiz kılınan nesneler bunu engellemiyorsa yürütmeye devam etmelidir. Örneğin, bir kaynağın güncellenmesi için güvenli paradigma şöyle olacaktır:

acquire lock
try
  update guarded resource
if exception
  invalidate lock
else
  release lock
end try

Korunan kaynak güncellenirken beklenmeyen bir istisna meydana gelirse, kaynağın bozuk bir durumda olduğu varsayılmalı ve istisnanın iyi niyetli bir tür olup olmamasına bakılmaksızın kilit geçersiz sayılmalıdır.

Ne yazık ki, korunan blok ne zaman çıksa, blokun normal mi yoksa anormal bir şekilde mi çıktığını bilmenin bir yolu olmadan, IDisposable/ aracılığıyla uygulanan kaynak korumaları usingserbest bırakılacaktır. Dolayısıyla, bir istisnadan sonra ne zaman devam edileceğine dair iyi tanımlanmış kriterler olsa da, ne zaman uygulanacaklarını söylemenin bir yolu yoktur.


+1 basitçe bu görece açık olmayan ve hala ortak olmayan perspektifi ifade etmek için doğru yolun ne olduğudur. Aslında bunu henüz kabul edersem bilmiyorum, çünkü bu benim için yeni bir sezgisel / kural.
mtraceur

0

Her bir iOS ve MacOS uygulamasının takip ettiği yaklaşımı kullanabilirsiniz: Yakalanmamış bir istisna, uygulamayı derhal durdurur. Ayrıca, sınırlar dizisi veya yeni uygulamalarda aritmetik taşma gibi birçok hata da aynı şeyi yapar. Uyarı yok.

Deneyimlerime göre, birçok kullanıcı herhangi bir bildirimde bulunmuyor, ancak uygulama simgesine tekrar dokunun.

Açıkçası, böyle bir kazanın önemli veri kaybına yol açmadığından ve kesinlikle yüksek maliyetli hatalara yol açmadığından emin olmanız gerekir. Ancak bir uyarı “Uygulamanız şimdi çökecek. Sizi rahatsız ediyorsa destek çağırın ”hiç kimseye yardımcı olmuyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.