Для начала, что значит каждые 15 минут:
- между соседними выполнениями
- между началами запуска
В первом случае просто: вынести логику в отдельную функцию и после каждого запуска засыпать.
Во втором случае надо замерять длительность выполнения: перед запуском сохраняешь время, а после получаешь конец и засыпаешь на оставшееся время
На счет Thread.Sleep - это ок, но если код асинхронный, то используй Task.Delay