Issue with synchronous HTTP post from background

Hey there,

I'm currently trying to create a HTTP post task which is being invoked by iOS shortcuts. It works as intended whenever the app is in the foreground. When I swap to the background, the task fails from time to time (probably 50/50 chance).

I'm a complete beginner when it comes to Swift so I'm scratching my head over this issue.

The reason I'm using the extension in combination with the synchronous method is because I'm unable to await for the result code before returning my statement.

Any ideas why it fails?

Code:

    static func SendTest(arg para:String) async -> Int {
        var answer = 0;
        guard let urlg = URL(string: "https://example.com/senden")
 else {
 fatalError("Missing URL")
 }
        var request = URLRequest(url: urlg)
        request.httpBody = Data(para.utf8)
        request.httpMethod = "PUT"
        let (_, response, error) = URLSession.shared.synchronousDataTask(urlrequest: request)
        if let error = error {
            print("Synchronous task ended with error: \(error)")
            answer = 0;
        }
        else {
            if ((response as? HTTPURLResponse)?.statusCode == 200){
                print ("works");
                answer = 1;
            }
                }
        return answer;
    }

extension URLSession {
    func synchronousDataTask(urlrequest: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) {
        var data: Data?
        var response: URLResponse?
        var error: Error?
        let semaphore = DispatchSemaphore(value: 0)
        let dataTask = self.dataTask(with: urlrequest) {
            data = $0
            response = $1
            error = $2
            semaphore.signal()
        }
        dataTask.resume()
        _ = semaphore.wait(timeout: .distantFuture)
        return (data, response, error)
    }   
}

Error message:

TestAppSiri[3908:1304888] [connection] nw_read_request_report [C15] Receive failed with error "Socket is not connected"\
2023-06-15 12:21:48.824337+0200 TestAppSiri[3908:1304888] [connection] nw_read_request_report [C15] Receive failed with error "Socket is not connected"\
2023-06-15 12:21:48.824462+0200 TestAppSiri[3908:1304888] [connection] nw_read_request_report [C15] Receive failed with error "Socket is not connected"\
2023-06-15 12:21:48.824582+0200 TestAppSiri[3908:1304888] [connection] nw_read_request_report [C15] Receive failed with error "Socket is not connected"\
2023-06-15 12:21:48.825674+0200 TestAppSiri[3908:1304888] [] nw_flow_service_writes Failing write request <nw_write_request> [57: Socket is not connected]\
2023-06-15 12:21:48.825744+0200 TestAppSiri[3908:1304888] [connection] nw_write_request_report [C15] Send failed with error "Socket is not connected"\
2023-06-15 12:21:48.825819+0200 TestAppSiri[3908:1304888] Connection 15: write error 1:57\
2023-06-15 12:21:48.826795+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.826852+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.826889+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.826924+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.826959+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.827030+0200 TestAppSiri[3908:1304888] [quic] quic_conn_send_frames_for_key_state_block_invoke [C15.1.1.1:2] [-01a5fbe8eeca39a6f0a5cbe8baca149ecd84a397] unable to request outbound data\
2023-06-15 12:21:48.828199+0200 TestAppSiri[3908:1304888] Task <974D40F7-6907-4C32-87F5-572C84501D2E>.<19> HTTP load failed, 103/0 bytes (error code: -1005 [1:57])\
2023-06-15 12:21:48.828471+0200 TestAppSiri[3908:1304888] Connection 15: received failure notification\
2023-06-15 12:21:48.828716+0200 TestAppSiri[3908:1310080] [connection] nw_endpoint_handler_unregister_context [C15.1.1.1 2606:4700:3035::ac43:b7d9.443 failed channel-flow (satisfied (Path is satisfied), viable, interface: pdp_ip0[lte], ipv4, ipv6, dns, expensive)] Cannot unregister after flow table is released\
2023-06-15 12:21:48.828847+0200 TestAppSiri[3908:1304888] Task <974D40F7-6907-4C32-87F5-572C84501D2E>.<19> finished with error [-1005] Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo=\{_kCFStreamErrorCodeKey=57, NSUnderlyingError=0x2828356e0 \{Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo=\{NSErrorPeerAddressKey=<CFData 0x280250420 [0x1f056eb78]>\{length = 28, capacity = 28, bytes = 0x1c1e01bb000000002606470030350000 ... ac43b7d900000000\}, _kCFStreamErrorCodeKey=57, _kCFStreamErrorDomainKey=1\}\}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <974D40F7-6907-4C32-87F5-572C84501D2E>.<19>, _NSURLErrorRelatedURLSessionTaskErrorKey=(\
    "LocalDataTask <974D40F7-6907-4C32-87F5-572C84501D2E>.<19>"\
), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://example.com/send/senden, NSErrorFailingURLKey=https://example.com/send/senden, _kCFStreamErrorDomainKey=1\}\
2023-06-15 12:21:48.828851+0200 TestAppSiri[3908:1310080] [] nw_endpoint_flow_fillout_data_transfer_snapshot copy_info() returned NULL\
Synchronous task ended with error: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo=\{_kCFStreamErrorCodeKey=57, NSUnderlyingError=0x2828356e0 \{Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo=\{NSErrorPeerAddressKey=<CFData 0x280250420 [0x1f056eb78]>\{length = 28, capacity = 28, bytes = 0x1c1e01bb000000002606470030350000 ... ac43b7d900000000\}, _kCFStreamErrorCodeKey=57, _kCFStreamErrorDomainKey=1\}\}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <974D40F7-6907-4C32-87F5-572C84501D2E>.<19>, _NSURLErrorRelatedURLSessionTaskErrorKey=(\
    "LocalDataTask <974D40F7-6907-4C32-87F5-572C84501D2E>.<19>"\
), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://example.com/send/senden, NSErrorFailingURLKey=https://example.com/send/senden, _kCFStreamErrorDomainKey=1\}}

Thanks in advance

There are three interlocking issues here:

  • Semaphores

  • Background execution

  • Shortcuts

Using a semaphore to turn an asynchronous call into a synchronous one is a major anti-pattern. It can result in all sorts of weird behaviour. More on this below.

As to the specific error you’re getting, that’s probably because your app is being suspended while the network operation is in flight. There are two standard ways around this:

Regarding this:

The reason I'm using the extension in combination with the synchronous method is because I'm unable to await for the result code before returning my statement.

Can you explain more about this requirement? Is that being imposed on you by the fact that you’re being run by Shortcuts? Or is it just the way that you’ve written your code?

Because my general advice on this front is to switch to using a Swift async function. This is as easy as writing synchronous code but avoids all the problems associated with using a semaphore.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Can you explain more about this requirement? Is that being imposed on you by the fact that you’re being run by Shortcuts? Or is it just the way that you’ve written your code?

Just me being unable to code it properly. I started with the async method but the function wouldn't await the async task (I'm more familiar with c#).

Somehow it works perfectly fine if I use http instead of https (both in background and foreground).

Issue with synchronous HTTP post from background
 
 
Q